Skip to content

Commit 58325ea

Browse files
YangSen-qnYangSen-qn
and
YangSen-qn
authored
fix: get url auth (#21)
* fix: get url auth * chore: version to 1.2.1 --------- Co-authored-by: YangSen-qn <yangsen@qiniu.com>
1 parent e489fdd commit 58325ea

File tree

7 files changed

+60
-17
lines changed

7 files changed

+60
-17
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# v1.2.1
2+
- 处理多媒体签名问题
3+
14
# v1.2.0
25
- 支持文件上传至七牛 Bucket
36

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "qiniu-mcp-server"
3-
version = "1.2.0"
3+
version = "1.2.1"
44
description = "A MCP server project of Qiniu."
55
requires-python = ">=3.12"
66
authors = [

src/mcp_server/core/media_processing/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
def load(cfg: config.Config):
77
cli = processing.MediaProcessingService(cfg)
8-
register_tools(cli)
8+
register_tools(cfg, cli)
99

1010

1111
__all__ = [

src/mcp_server/core/media_processing/tools.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import logging
2+
3+
import qiniu
24
from mcp import types
35

46
from . import utils
57
from .processing import MediaProcessingService
8+
from ...config import config
69
from ...consts import consts
710
from ...tools import tools
811

@@ -12,7 +15,8 @@
1215

1316

1417
class _ToolImpl:
15-
def __init__(self, cli: MediaProcessingService):
18+
def __init__(self, cfg: config.Config, cli: MediaProcessingService):
19+
self.auth = qiniu.Auth(cfg.access_key, cfg.secret_key)
1620
self.client = cli
1721

1822
@tools.tool_meta(
@@ -55,8 +59,8 @@ def image_scale_by_percent(
5559
types.TextContent(type="text", text="percent must be between 1 and 999")
5660
]
5761

58-
fop = f"imageMogr2/thumbnail/!{percent}p"
59-
object_url = utils.url_add_processing_func(object_url, fop)
62+
func = f"imageMogr2/thumbnail/!{percent}p"
63+
object_url = utils.url_add_processing_func(auth=self.auth, url=object_url, func=func)
6064
return [
6165
types.TextContent(
6266
type="text",
@@ -111,16 +115,16 @@ def image_scale_by_size(
111115
if object_url is None or len(object_url) == 0:
112116
return [types.TextContent(type="text", text="object_url is required")]
113117

114-
fop = f"{width}x{height}"
115-
if len(fop) == 1:
118+
func = f"{width}x{height}"
119+
if len(func) == 1:
116120
return [
117121
types.TextContent(
118122
type="text", text="At least one width or height must be set"
119123
)
120124
]
121125

122-
fop = f"imageMogr2/thumbnail/{fop}"
123-
object_url = utils.url_add_processing_func(object_url, fop)
126+
func = f"imageMogr2/thumbnail/{func}"
127+
object_url = utils.url_add_processing_func(auth=self.auth, url=object_url, func=func)
124128
return [
125129
types.TextContent(
126130
type="text",
@@ -191,7 +195,7 @@ def image_round_corner(self, **kwargs) -> list[types.TextContent]:
191195
radius_y = radius_x
192196

193197
func = f"roundPic/radiusx/{radius_x}/radiusy/{radius_y}"
194-
object_url = utils.url_add_processing_func(object_url, func)
198+
object_url = utils.url_add_processing_func(auth=self.auth, url=object_url, func=func)
195199
return [
196200
types.TextContent(
197201
type="text",
@@ -228,7 +232,7 @@ def image_info(self, **kwargs) -> list[types.TextContent]:
228232
]
229233

230234
func = "imageInfo"
231-
object_url = utils.url_add_processing_func(object_url, func)
235+
object_url = utils.url_add_processing_func(auth=self.auth, url=object_url, func=func)
232236
return [
233237
types.TextContent(
234238
type="text",
@@ -259,8 +263,8 @@ def get_fop_status(self, **kwargs) -> list[types.TextContent]:
259263
return [types.TextContent(type="text", text=str(status))]
260264

261265

262-
def register_tools(cli: MediaProcessingService):
263-
tool_impl = _ToolImpl(cli)
266+
def register_tools(cfg: config.Config, cli: MediaProcessingService):
267+
tool_impl = _ToolImpl(cfg, cli)
264268
tools.auto_register_tools(
265269
[
266270
tool_impl.image_scale_by_percent,

src/mcp_server/core/media_processing/utils.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
import time
12
from urllib import parse
23

4+
import qiniu
5+
6+
from mcp_server.core.storage.tools import logger
7+
38
FUNC_POSITION_NONE = "none"
49
FUNC_POSITION_PREFIX = "prefix"
510
FUNC_POSITION_SUFFIX = "suffix"
611

712

8-
def url_add_processing_func(url: str, func: str) -> str:
13+
def url_add_processing_func(auth: qiniu.auth, url: str, func: str) -> str:
914
func_items = func.split("/")
1015
func_prefix = func_items[0]
1116

@@ -14,7 +19,8 @@ def url_add_processing_func(url: str, func: str) -> str:
1419
new_query = parse.quote(new_query, safe='&=')
1520
url_info = url_info._replace(query=new_query)
1621
new_url = parse.urlunparse(url_info)
17-
return str(new_url)
22+
new_url = _sign_url(str(new_url), auth)
23+
return new_url
1824

1925

2026
def _query_add_processing_func(query: str, func: str, func_prefix: str) -> str:
@@ -70,3 +76,33 @@ def _query_add_processing_func(query: str, func: str, func_prefix: str) -> str:
7076
func = first_query + func.removeprefix(func_prefix)
7177
queries.insert(0, func)
7278
return "&".join(queries)
79+
80+
81+
def _sign_url(url: str, auth: qiniu.auth) -> str:
82+
url_info = parse.urlparse(url)
83+
query = url_info.query
84+
if ('e=' not in query) or ('token=' not in query):
85+
return url
86+
87+
queries = query.split("&")
88+
if '' in queries:
89+
queries.remove('')
90+
91+
# 移除之前的签名信息,但顺序不可变
92+
expires = 3600
93+
new_queries = []
94+
for query_item in queries:
95+
if query_item.startswith('e='):
96+
try:
97+
deadline = int(query_item.removeprefix('e='))
98+
expires = deadline - int(time.time())
99+
except Exception as e:
100+
logger.warning(f"expires parse fail for url:{url} err:{str(e)}")
101+
expires = 3600
102+
elif not query_item.startswith('token='):
103+
new_queries.append(query_item)
104+
105+
new_query = "&".join(new_queries)
106+
url_info = url_info._replace(query=new_query)
107+
new_url = parse.urlunparse(url_info)
108+
return auth.private_download_url(new_url, expires=expires)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11

2-
VERSION = '1.2.0'
2+
VERSION = '1.2.1'

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)