Skip to content

Commit 2339454

Browse files
xrgzsCopilot
andauthored
feat(123_open): add DirectLink option (#1045)
* feat(123_open): add `UseDirectLink` option * feat(123_open): update rate limit rules * fix(123_open): update api Co-authored-by: Copilot <[email protected]> Signed-off-by: MadDogOwner <[email protected]> * feat(123_open): enhance direct link functionality with private key and expiration * refactor(123_open): use UUID for random generation --------- Signed-off-by: MadDogOwner <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent b04677b commit 2339454

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

drivers/123_open/driver.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,45 @@ func (d *Open123) List(ctx context.Context, dir model.Obj, args model.ListArgs)
6969
func (d *Open123) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
7070
fileId, _ := strconv.ParseInt(file.GetID(), 10, 64)
7171

72+
if d.DirectLink {
73+
res, err := d.getDirectLink(fileId)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
if d.DirectLinkPrivateKey == "" {
79+
duration := 365 * 24 * time.Hour // 缓存1年
80+
return &model.Link{
81+
URL: res.Data.URL,
82+
Expiration: &duration,
83+
}, nil
84+
}
85+
86+
u, err := d.getUserInfo()
87+
if err != nil {
88+
return nil, err
89+
}
90+
91+
duration := time.Duration(d.DirectLinkValidDuration) * time.Minute
92+
93+
newURL, err := d.SignURL(res.Data.URL, d.DirectLinkPrivateKey,
94+
u.Data.UID, duration)
95+
if err != nil {
96+
return nil, err
97+
}
98+
99+
return &model.Link{
100+
URL: newURL,
101+
Expiration: &duration,
102+
}, nil
103+
}
104+
72105
res, err := d.getDownloadInfo(fileId)
73106
if err != nil {
74107
return nil, err
75108
}
76109

77-
link := model.Link{URL: res.Data.DownloadUrl}
78-
return &link, nil
110+
return &model.Link{URL: res.Data.DownloadUrl}, nil
79111
}
80112

81113
func (d *Open123) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {

drivers/123_open/meta.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ type Addition struct {
2323
// 上传线程数
2424
UploadThread int `json:"UploadThread" type:"number" default:"3" help:"the threads of upload"`
2525

26+
// 使用直链
27+
DirectLink bool `json:"DirectLink" type:"boolean" default:"false" required:"false" help:"use direct link when download file"`
28+
DirectLinkPrivateKey string `json:"DirectLinkPrivateKey" required:"false" help:"private key for direct link, if URL authentication is enabled"`
29+
DirectLinkValidDuration int64 `json:"DirectLinkValidDuration" type:"number" default:"30" required:"false" help:"minutes, if URL authentication is enabled"`
30+
2631
driver.RootID
2732
}
2833

drivers/123_open/types.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ type RefreshTokenResp struct {
127127
type UserInfoResp struct {
128128
BaseResp
129129
Data struct {
130-
UID int64 `json:"uid"`
130+
UID uint64 `json:"uid"`
131131
Username string `json:"username"`
132132
DisplayName string `json:"displayName"`
133133
HeadImage string `json:"headImage"`
@@ -158,6 +158,13 @@ type DownloadInfoResp struct {
158158
} `json:"data"`
159159
}
160160

161+
type DirectLinkResp struct {
162+
BaseResp
163+
Data struct {
164+
URL string `json:"url"`
165+
} `json:"data"`
166+
}
167+
161168
// 创建文件V2返回
162169
type UploadCreateResp struct {
163170
BaseResp

drivers/123_open/util.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
package _123_open
22

33
import (
4+
"crypto/md5"
45
"encoding/json"
56
"errors"
7+
"fmt"
68
"net/http"
9+
"net/url"
710
"strconv"
11+
"strings"
812
"time"
913

1014
"github.com/OpenListTeam/OpenList/v4/drivers/base"
1115
"github.com/OpenListTeam/OpenList/v4/internal/op"
1216
"github.com/go-resty/resty/v2"
17+
"github.com/google/uuid"
1318
log "github.com/sirupsen/logrus"
1419
)
1520

@@ -20,7 +25,8 @@ var ( //不同情况下获取的AccessTokenQPS限制不同 如下模块化易于
2025
RefreshToken = InitApiInfo(Api+"/api/v1/oauth2/access_token", 1)
2126
UserInfo = InitApiInfo(Api+"/api/v1/user/info", 1)
2227
FileList = InitApiInfo(Api+"/api/v2/file/list", 3)
23-
DownloadInfo = InitApiInfo(Api+"/api/v1/file/download_info", 0)
28+
DownloadInfo = InitApiInfo(Api+"/api/v1/file/download_info", 5)
29+
DirectLink = InitApiInfo(Api+"/api/v1/direct-link/url", 5)
2430
Mkdir = InitApiInfo(Api+"/upload/v1/file/mkdir", 2)
2531
Move = InitApiInfo(Api+"/api/v1/file/move", 1)
2632
Rename = InitApiInfo(Api+"/api/v1/file/name", 1)
@@ -112,6 +118,33 @@ func (d *Open123) flushAccessToken() error {
112118
return nil
113119
}
114120

121+
func (d *Open123) SignURL(originURL, privateKey string, uid uint64, validDuration time.Duration) (newURL string, err error) {
122+
// 生成Unix时间戳
123+
ts := time.Now().Add(validDuration).Unix()
124+
125+
// 生成随机数(建议使用UUID,不能包含中划线(-))
126+
rand := strings.ReplaceAll(uuid.New().String(), "-", "")
127+
128+
// 解析URL
129+
objURL, err := url.Parse(originURL)
130+
if err != nil {
131+
return "", err
132+
}
133+
134+
// 待签名字符串,格式:path-timestamp-rand-uid-privateKey
135+
unsignedStr := fmt.Sprintf("%s-%d-%s-%d-%s", objURL.Path, ts, rand, uid, privateKey)
136+
md5Hash := md5.Sum([]byte(unsignedStr))
137+
// 生成鉴权参数,格式:timestamp-rand-uid-md5hash
138+
authKey := fmt.Sprintf("%d-%s-%d-%x", ts, rand, uid, md5Hash)
139+
140+
// 添加鉴权参数到URL查询参数
141+
v := objURL.Query()
142+
v.Add("auth_key", authKey)
143+
objURL.RawQuery = v.Encode()
144+
145+
return objURL.String(), nil
146+
}
147+
115148
func (d *Open123) getUserInfo() (*UserInfoResp, error) {
116149
var resp UserInfoResp
117150

@@ -159,6 +192,21 @@ func (d *Open123) getDownloadInfo(fileId int64) (*DownloadInfoResp, error) {
159192
return &resp, nil
160193
}
161194

195+
func (d *Open123) getDirectLink(fileId int64) (*DirectLinkResp, error) {
196+
var resp DirectLinkResp
197+
198+
_, err := d.Request(DirectLink, http.MethodGet, func(req *resty.Request) {
199+
req.SetQueryParams(map[string]string{
200+
"fileId": strconv.FormatInt(fileId, 10),
201+
})
202+
}, &resp)
203+
if err != nil {
204+
return nil, err
205+
}
206+
207+
return &resp, nil
208+
}
209+
162210
func (d *Open123) mkdir(parentID int64, name string) error {
163211
_, err := d.Request(Mkdir, http.MethodPost, func(req *resty.Request) {
164212
req.SetBody(base.Json{

0 commit comments

Comments
 (0)