Skip to content

Commit 0fb2666

Browse files
committed
Fully implemented PW change, refactoring, only display files if user has permission in UI, TODO: disable UI elements in upload view if no permission
1 parent 092a320 commit 0fb2666

File tree

11 files changed

+200
-78
lines changed

11 files changed

+200
-78
lines changed

docs/setup.rst

+1
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ This option disables Gokapis internal authentication completely, except for API
229229

230230
- ``/admin``
231231
- ``/apiKeys``
232+
- ``/changePassword``
232233
- ``/e2eInfo``
233234
- ``/e2eSetup``
234235
- ``/logs``

internal/configuration/setup/ProtectedUrls.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ package setup
55

66
// protectedUrls contains a list of URLs that need to be protected if authentication is disabled.
77
// This list will be displayed during the setup
8-
var protectedUrls = []string{"/admin", "/apiKeys", "/e2eInfo", "/e2eSetup", "/logs", "/uploadChunk", "/uploadComplete", "/uploadStatus", "/users"}
8+
var protectedUrls = []string{"/admin", "/apiKeys", "/changePassword", "/e2eInfo", "/e2eSetup", "/logs", "/uploadChunk", "/uploadComplete", "/uploadStatus", "/users"}

internal/webserver/Webserver.go

+101-40
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,14 @@ func Start() {
9191
}
9292
loadExpiryImage()
9393

94-
mux.HandleFunc("/admin", requireLogin(showAdminMenu, false))
94+
mux.HandleFunc("/admin", requireLogin(showAdminMenu, true, false))
9595
mux.HandleFunc("/api/", processApi)
96-
mux.HandleFunc("/apiKeys", requireLogin(showApiAdmin, false))
96+
mux.HandleFunc("/apiKeys", requireLogin(showApiAdmin, true, false))
97+
mux.HandleFunc("/changePassword", requireLogin(changePassword, true, true))
9798
mux.HandleFunc("/d", showDownload)
9899
mux.HandleFunc("/downloadFile", downloadFile)
99-
mux.HandleFunc("/e2eInfo", requireLogin(e2eInfo, true))
100-
mux.HandleFunc("/e2eSetup", requireLogin(showE2ESetup, false))
100+
mux.HandleFunc("/e2eInfo", requireLogin(e2eInfo, true, false))
101+
mux.HandleFunc("/e2eSetup", requireLogin(showE2ESetup, true, false))
101102
mux.HandleFunc("/error", showError)
102103
mux.HandleFunc("/error-auth", showErrorAuth)
103104
mux.HandleFunc("/error-header", showErrorHeader)
@@ -106,12 +107,12 @@ func Start() {
106107
mux.HandleFunc("/hotlink/", showHotlink)
107108
mux.HandleFunc("/index", showIndex)
108109
mux.HandleFunc("/login", showLogin)
109-
mux.HandleFunc("/logs", requireLogin(showLogs, false))
110+
mux.HandleFunc("/logs", requireLogin(showLogs, true, false))
110111
mux.HandleFunc("/logout", doLogout)
111-
mux.HandleFunc("/uploadChunk", requireLogin(uploadChunk, true))
112-
mux.HandleFunc("/uploadComplete", requireLogin(uploadComplete, true))
113-
mux.HandleFunc("/uploadStatus", requireLogin(sse.GetStatusSSE, true))
114-
mux.HandleFunc("/users", requireLogin(showUserAdmin, false))
112+
mux.HandleFunc("/uploadChunk", requireLogin(uploadChunk, true, false))
113+
mux.HandleFunc("/uploadComplete", requireLogin(uploadComplete, true, false))
114+
mux.HandleFunc("/uploadStatus", requireLogin(sse.GetStatusSSE, true, false))
115+
mux.HandleFunc("/users", requireLogin(showUserAdmin, true, false))
115116
mux.Handle("/main.wasm", gziphandler.GzipHandler(http.HandlerFunc(serveDownloadWasm)))
116117
mux.Handle("/e2e.wasm", gziphandler.GzipHandler(http.HandlerFunc(serveE2EWasm)))
117118

@@ -256,6 +257,57 @@ func showIndex(w http.ResponseWriter, r *http.Request) {
256257
helper.CheckIgnoreTimeout(err)
257258
}
258259

260+
// Handling of /changePassword
261+
func changePassword(w http.ResponseWriter, r *http.Request) {
262+
var errMessage string
263+
user, err := authentication.GetUserFromRequest(r)
264+
if err != nil {
265+
panic(err)
266+
}
267+
if !user.ResetPassword {
268+
redirect(w, "admin")
269+
return
270+
}
271+
err = r.ParseForm()
272+
if err != nil {
273+
fmt.Println("Invalid form data sent to server for /changePassword")
274+
fmt.Println(err)
275+
errMessage = "Invalid form data sent"
276+
} else {
277+
var ok bool
278+
var pwHash string
279+
280+
pw := r.Form.Get("newpw")
281+
errMessage, pwHash, ok = validateNewPassword(pw, user)
282+
if ok {
283+
user.Password = pwHash
284+
user.ResetPassword = false
285+
database.SaveUser(user, false)
286+
redirect(w, "admin")
287+
return
288+
}
289+
}
290+
err = templateFolder.ExecuteTemplate(w, "changepw",
291+
genericView{PublicName: configuration.Get().PublicName,
292+
MinPasswordLength: configuration.MinLengthPassword,
293+
ErrorMessage: errMessage})
294+
helper.CheckIgnoreTimeout(err)
295+
}
296+
297+
func validateNewPassword(newPassword string, user models.User) (string, string, bool) {
298+
if len(newPassword) == 0 {
299+
return "", user.Password, false
300+
}
301+
if len(newPassword) < configuration.MinLengthPassword {
302+
return "Password is too short", user.Password, false
303+
}
304+
newPasswordHash := configuration.HashPassword(newPassword, false)
305+
if user.Password == newPasswordHash {
306+
return "New password has to be different from the old password", user.Password, false
307+
}
308+
return "", newPasswordHash, true
309+
}
310+
259311
// Handling of /error
260312
func showError(w http.ResponseWriter, r *http.Request) {
261313
const invalidFile = 0
@@ -305,7 +357,7 @@ func forgotPassword(w http.ResponseWriter, r *http.Request) {
305357
// Handling of /api
306358
// If user is authenticated, this menu lists all uploads and enables uploading new files
307359
func showApiAdmin(w http.ResponseWriter, r *http.Request) {
308-
userId, err := authentication.GetUserIdFromRequest(r)
360+
userId, err := authentication.GetUserFromRequest(r)
309361
if err != nil {
310362
panic(err)
311363
}
@@ -317,7 +369,7 @@ func showApiAdmin(w http.ResponseWriter, r *http.Request) {
317369
// Handling of /users
318370
// If user is authenticated, this menu lists all users
319371
func showUserAdmin(w http.ResponseWriter, r *http.Request) {
320-
userId, err := authentication.GetUserIdFromRequest(r)
372+
userId, err := authentication.GetUserFromRequest(r)
321373
if err != nil {
322374
panic(err)
323375
}
@@ -480,16 +532,16 @@ func e2eInfo(w http.ResponseWriter, r *http.Request) {
480532
return
481533
}
482534

483-
userId, err := authentication.GetUserIdFromRequest(r)
535+
user, err := authentication.GetUserFromRequest(r)
484536
if err != nil {
485537
responseError(w, err)
486538
return
487539
}
488540
switch action[0] {
489541
case "get":
490-
getE2eInfo(w, userId)
542+
getE2eInfo(w, user.Id)
491543
case "store":
492-
storeE2eInfo(w, r, userId)
544+
storeE2eInfo(w, r, user.Id)
493545
default:
494546
responseError(w, errors.New("invalid action specified"))
495547
}
@@ -546,26 +598,26 @@ func queryUrl(w http.ResponseWriter, r *http.Request, redirectUrl string) string
546598
// If user is authenticated, this menu lists all uploads and enables uploading new files
547599
func showAdminMenu(w http.ResponseWriter, r *http.Request) {
548600

549-
userId, err := authentication.GetUserIdFromRequest(r)
601+
user, err := authentication.GetUserFromRequest(r)
550602
if err != nil {
551603
panic(err)
552604
}
553605

554606
if configuration.Get().Encryption.Level == encryption.EndToEndEncryption {
555-
e2einfo := database.GetEnd2EndInfo(userId)
607+
e2einfo := database.GetEnd2EndInfo(user.Id)
556608
if !e2einfo.HasBeenSetUp() {
557609
redirect(w, "e2eSetup")
558610
return
559611
}
560612
}
561-
err = templateFolder.ExecuteTemplate(w, "admin", (&UploadView{}).convertGlobalConfig(ViewMain, userId))
613+
err = templateFolder.ExecuteTemplate(w, "admin", (&UploadView{}).convertGlobalConfig(ViewMain, user))
562614
helper.CheckIgnoreTimeout(err)
563615
}
564616

565617
// Handling of /logs
566618
// If user is authenticated, this menu shows the stored logs
567619
func showLogs(w http.ResponseWriter, r *http.Request) {
568-
userId, err := authentication.GetUserIdFromRequest(r)
620+
userId, err := authentication.GetUserFromRequest(r)
569621
if err != nil {
570622
panic(err)
571623
}
@@ -584,11 +636,11 @@ func showE2ESetup(w http.ResponseWriter, r *http.Request) {
584636
return
585637
}
586638

587-
userId, err := authentication.GetUserIdFromRequest(r)
639+
user, err := authentication.GetUserFromRequest(r)
588640
if err != nil {
589641
panic(err)
590642
}
591-
e2einfo := database.GetEnd2EndInfo(userId)
643+
e2einfo := database.GetEnd2EndInfo(user.Id)
592644
err = templateFolder.ExecuteTemplate(w, "e2esetup", e2ESetupView{HasBeenSetup: e2einfo.HasBeenSetUp(), PublicName: configuration.Get().PublicName})
593645
helper.CheckIgnoreTimeout(err)
594646
}
@@ -635,6 +687,7 @@ type UploadView struct {
635687
IsUserTabAvailable bool
636688
EndToEndEncryption bool
637689
IncludeFilename bool
690+
IsInternalAuth bool
638691
MaxFileSize int
639692
ActiveView int
640693
ChunkSize int
@@ -666,20 +719,20 @@ const (
666719

667720
// Converts the globalConfig variable to an UploadView struct to pass the infos to
668721
// the admin template
669-
func (u *UploadView) convertGlobalConfig(view, userId int) *UploadView {
722+
func (u *UploadView) convertGlobalConfig(view int, user models.User) *UploadView {
670723
var result []models.FileApiOutput
671724
var resultApi []models.ApiKey
672725

673-
user, ok := database.GetUser(userId)
674-
if !ok {
675-
panic("user not found")
676-
}
726+
config := configuration.Get()
727+
u.IsInternalAuth = config.Authentication.Method == models.AuthenticationInternal
677728
u.ActiveUser = user
678729
u.UserMap = getUserMap()
679-
config := configuration.Get()
680730
switch view {
681731
case ViewMain:
682732
for _, element := range database.GetAllMetadata() {
733+
if element.UserId != user.Id && !user.HasPermissionListOtherUploads() {
734+
continue
735+
}
683736
fileInfo, err := element.ToFileApiOutput(config.ServerUrl, config.IncludeFilename)
684737
helper.Check(err)
685738
result = append(result, fileInfo)
@@ -695,7 +748,7 @@ func (u *UploadView) convertGlobalConfig(view, userId int) *UploadView {
695748
// Double-checking if user of API key exists
696749
// If the user was manually deleted from the database, this could lead to a crash
697750
// in the API view
698-
_, ok = u.UserMap[apiKey.UserId]
751+
_, ok := u.UserMap[apiKey.UserId]
699752
if !ok {
700753
continue
701754
}
@@ -728,7 +781,7 @@ func (u *UploadView) convertGlobalConfig(view, userId int) *UploadView {
728781
User: userEntry,
729782
}
730783
// Otherwise the user is not shown as online, if /users is opened as first page
731-
if userEntry.Id == userId {
784+
if userEntry.Id == user.Id {
732785
userWithUploads.User.LastOnline = time.Now().Unix()
733786
}
734787
u.Users = append(u.Users, userWithUploads)
@@ -749,7 +802,7 @@ func (u *UploadView) convertGlobalConfig(view, userId int) *UploadView {
749802
u.MaxParallelUploads = config.MaxParallelUploads
750803
u.ChunkSize = config.ChunkSize
751804
u.IncludeFilename = config.IncludeFilename
752-
u.SystemKey = api.GetSystemKey(userId)
805+
u.SystemKey = api.GetSystemKey(user.Id)
753806
return u
754807
}
755808

@@ -780,12 +833,12 @@ func uploadComplete(w http.ResponseWriter, r *http.Request) {
780833
responseError(w, err)
781834
return
782835
}
783-
userId, err := authentication.GetUserIdFromRequest(r)
836+
user, err := authentication.GetUserFromRequest(r)
784837
if err != nil {
785838
panic(err)
786839
}
787840
go func() {
788-
_, err = fileupload.CompleteChunk(chunkId, header, userId, config)
841+
_, err = fileupload.CompleteChunk(chunkId, header, user.Id, config)
789842
if err != nil {
790843
processingstatus.Set(chunkId, processingstatus.StatusError, models.File{}, err)
791844
fmt.Println(err)
@@ -843,17 +896,23 @@ func serveFile(id string, isRootUrl bool, w http.ResponseWriter, r *http.Request
843896
storage.ServeFile(savedFile, w, r, true)
844897
}
845898

846-
func requireLogin(next http.HandlerFunc, isUpload bool) http.HandlerFunc {
899+
func requireLogin(next http.HandlerFunc, isUiCall, isPwChangeView bool) http.HandlerFunc {
847900
return func(w http.ResponseWriter, r *http.Request) {
848901
addNoCacheHeader(w)
849-
isLoggedIn, userId := authentication.IsAuthenticated(w, r)
902+
isLoggedIn, user := authentication.IsAuthenticated(w, r)
850903
if isLoggedIn {
851-
c := context.WithValue(r.Context(), "userId", userId)
904+
if user.ResetPassword && isUiCall && configuration.Get().Authentication.Method == models.AuthenticationInternal {
905+
if !isPwChangeView {
906+
redirect(w, "changePassword")
907+
return
908+
}
909+
}
910+
c := context.WithValue(r.Context(), "user", user)
852911
r = r.WithContext(c)
853912
next.ServeHTTP(w, r)
854913
return
855914
}
856-
if isUpload {
915+
if !isUiCall {
857916
w.WriteHeader(http.StatusUnauthorized)
858917
_, _ = io.WriteString(w, "{\"Result\":\"error\",\"ErrorMessage\":\"Not authenticated\"}")
859918
return
@@ -893,11 +952,13 @@ func addNoCacheHeader(w http.ResponseWriter) {
893952

894953
// A view containing parameters for a generic template
895954
type genericView struct {
896-
IsAdminView bool
897-
IsDownloadView bool
898-
PublicName string
899-
RedirectUrl string
900-
ErrorId int
955+
IsAdminView bool
956+
IsDownloadView bool
957+
PublicName string
958+
RedirectUrl string
959+
ErrorMessage string
960+
ErrorId int
961+
MinPasswordLength int
901962
}
902963

903964
// A view containing parameters for an oauth error

internal/webserver/api/Api.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ func resetPw(w http.ResponseWriter, request apiRequest, user models.User) {
683683
userToEdit.ResetPassword = true
684684
password := ""
685685
if request.usermodInfo.setNewPw {
686-
password = helper.GenerateRandomString(10)
686+
password = helper.GenerateRandomString(configuration.MinLengthPassword + 2)
687687
userToEdit.Password = configuration.HashPassword(password, false)
688688
}
689689
database.SaveUser(userToEdit, false)

0 commit comments

Comments
 (0)