Skip to content

Commit 7e37c40

Browse files
authored
feat(sharing): allow custom share IDs (#2353)
feat: allow custom share IDs - Change sharing ID column from char(12) to varchar(64) - Add new_id field to UpdateSharingReq for renaming share IDs - Add ID validation (max 64 chars, alphanumeric/CJK/hyphens/underscores) - Add conflict check when updating share ID - Add customize_share_id permission (bit 15) Closes #1806
1 parent e28406f commit 7e37c40

5 files changed

Lines changed: 62 additions & 2 deletions

File tree

internal/db/sharing.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ func UpdateSharing(s *model.SharingDB) error {
6464
return errors.WithStack(db.Save(s).Error)
6565
}
6666

67+
func UpdateSharingId(oldId, newId string) error {
68+
// Check if new ID already exists
69+
if err := db.Where("id = ?", newId).First(&model.SharingDB{}).Error; err == nil {
70+
return errors.New("sharing id already exists")
71+
}
72+
return errors.WithStack(db.Model(&model.SharingDB{}).Where("id = ?", oldId).Update("id", newId).Error)
73+
}
74+
6775
func DeleteSharingById(id string) error {
6876
s := model.SharingDB{ID: id}
6977
return errors.WithStack(db.Where(s).Delete(&s).Error)

internal/model/sharing.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package model
33
import "time"
44

55
type SharingDB struct {
6-
ID string `json:"id" gorm:"type:char(12);primaryKey"`
6+
ID string `json:"id" gorm:"type:varchar(64);primaryKey"`
77
FilesRaw string `json:"-" gorm:"type:text"`
88
Expires *time.Time `json:"expires"`
99
Pwd string `json:"pwd"`

internal/model/user.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type User struct {
6363
// 12: can read archives
6464
// 13: can decompress archives
6565
// 14: can share
66+
// 15: can customize share id
6667
Permission int32 `json:"permission"`
6768
OtpSecret string `json:"-"`
6869
SsoID string `json:"sso_id"` // unique by sso platform
@@ -219,6 +220,14 @@ func (u *User) CanShare() bool {
219220
return CanShare(u.Permission)
220221
}
221222

223+
func CanCustomizeShareID(permission int32) bool {
224+
return (permission>>15)&1 == 1
225+
}
226+
227+
func (u *User) CanCustomizeShareID() bool {
228+
return CanCustomizeShareID(u.Permission)
229+
}
230+
222231
func (u *User) JoinPath(reqPath string) (string, error) {
223232
return utils.JoinBasePath(u.BasePath, reqPath)
224233
}

internal/op/sharing.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ func UpdateSharing(sharing *model.Sharing, skipMarshal ...bool) (err error) {
133133
return db.UpdateSharing(sharing.SharingDB)
134134
}
135135

136+
func UpdateSharingId(sharing *model.Sharing, newId string) error {
137+
sharingCache.Del(sharing.ID)
138+
if err := db.UpdateSharingId(sharing.ID, newId); err != nil {
139+
return err
140+
}
141+
sharing.ID = newId
142+
return nil
143+
}
144+
136145
func DeleteSharing(sid string) error {
137146
sharingCache.Del(sid)
138147
return db.DeleteSharingById(sid)

server/handles/sharing.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package handles
33
import (
44
"fmt"
55
stdpath "path"
6+
"regexp"
67
"strings"
78
"time"
89

@@ -416,6 +417,19 @@ type UpdateSharingReq struct {
416417
CreatorName string `json:"creator"`
417418
Accessed int `json:"accessed"`
418419
ID string `json:"id"`
420+
NewID string `json:"new_id"`
421+
}
422+
423+
var validSharingID = regexp.MustCompile(`^[\w\p{Han}\-]+$`)
424+
425+
func validateSharingID(id string) error {
426+
if len([]rune(id)) > 64 {
427+
return errors.New("share id must be at most 64 characters")
428+
}
429+
if !validSharingID.MatchString(id) {
430+
return errors.New("share id can only contain letters, numbers, underscores, hyphens, and CJK characters")
431+
}
432+
return nil
419433
}
420434

421435
func UpdateSharing(c *gin.Context) {
@@ -471,6 +485,20 @@ func UpdateSharing(c *gin.Context) {
471485
s.Readme = req.Readme
472486
s.Remark = req.Remark
473487
s.Creator = user
488+
if req.NewID != "" && req.NewID != req.ID {
489+
if !reqUser.CanCustomizeShareID() {
490+
common.ErrorStrResp(c, "permission denied", 403)
491+
return
492+
}
493+
if err = validateSharingID(req.NewID); err != nil {
494+
common.ErrorResp(c, err, 400)
495+
return
496+
}
497+
if err = op.UpdateSharingId(s, req.NewID); err != nil {
498+
common.ErrorResp(c, err, 500)
499+
return
500+
}
501+
}
474502
if err = op.UpdateSharing(s); err != nil {
475503
common.ErrorResp(c, err, 500)
476504
} else {
@@ -493,6 +521,12 @@ func CreateSharing(c *gin.Context) {
493521
common.ErrorStrResp(c, "must add at least 1 object", 400)
494522
return
495523
}
524+
if req.ID != "" {
525+
if err = validateSharingID(req.ID); err != nil {
526+
common.ErrorResp(c, err, 400)
527+
return
528+
}
529+
}
496530
var user *model.User
497531
reqUser := c.Request.Context().Value(conf.UserKey).(*model.User)
498532
if reqUser.IsAdmin() && req.CreatorName != "" {
@@ -503,7 +537,7 @@ func CreateSharing(c *gin.Context) {
503537
}
504538
} else {
505539
user = reqUser
506-
if !user.CanShare() || (!user.IsAdmin() && req.ID != "") {
540+
if !user.CanShare() || (!user.CanCustomizeShareID() && req.ID != "") {
507541
common.ErrorStrResp(c, "permission denied", 403)
508542
return
509543
}

0 commit comments

Comments
 (0)