Skip to content

Commit ee1a314

Browse files
carsonxuMolunerfinn
authored andcommitted
🐛 Fix(tcyun): compatible tencent cos bucket with strict signature mode enabled (#182)
1 parent f11cd93 commit ee1a314

1 file changed

Lines changed: 22 additions & 8 deletions

File tree

src/plugins/uploader/tcyun.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,20 @@ export interface ISignature {
1313
signTime: string
1414
}
1515

16-
const generateSignature = (options: ITcyunConfig, fileName: string): ISignature => {
16+
const cosSafeUrlEncode = (str: string): string => {
17+
return encodeURIComponent(str)
18+
.replace(/!/g, '%21')
19+
.replace(/'/g, '%27')
20+
.replace(/\(/g, '%28')
21+
.replace(/\)/g, '%29')
22+
.replace(/\*/g, '%2A')
23+
}
24+
25+
const generateContentType = (fileName: string): string => {
26+
return mime.lookup(fileName) || 'application/octet-stream'
27+
}
28+
29+
const generateSignature = (options: ITcyunConfig, fileName: string, contentType: string, contentLength: number): ISignature => {
1730
const secretId = options.secretId
1831
const secretKey = options.secretKey
1932
const appId = options.appId
@@ -37,7 +50,7 @@ const generateSignature = (options: ITcyunConfig, fileName: string): ISignature
3750
signTime = `${today};${tomorrow}`
3851
const signKey = crypto.createHmac('sha1', secretKey).update(signTime).digest('hex')
3952
const endpoint = options.endpoint ? options.endpoint : `cos.${options.area}.myqcloud.com`
40-
const httpString = `put\n/${options.path}${fileName}\n\nhost=${options.bucket}.${endpoint}\n`
53+
const httpString = `put\n/${options.path}${fileName}\n\ncontent-length=${contentLength}&content-type=${cosSafeUrlEncode(contentType)}&host=${options.bucket}.${endpoint}\n`
4154
const sha1edHttpString = crypto.createHash('sha1').update(httpString).digest('hex')
4255
const stringToSign = `sha1\n${signTime}\n${sha1edHttpString}\n`
4356
signature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex')
@@ -78,8 +91,9 @@ const postOptions = (options: ITcyunConfig, fileName: string, signature: ISignat
7891
url: `http://${options.bucket}.${endpoint}/${encodeURI(path)}${encodeURIComponent(fileName)}`,
7992
headers: {
8093
Host: `${options.bucket}.${endpoint}`,
81-
Authorization: `q-sign-algorithm=sha1&q-ak=${options.secretId}&q-sign-time=${signature.signTime}&q-key-time=${signature.signTime}&q-header-list=host&q-url-param-list=&q-signature=${signature.signature}`,
82-
contentType: mime.lookup(fileName),
94+
Authorization: `q-sign-algorithm=sha1&q-ak=${options.secretId}&q-sign-time=${signature.signTime}&q-key-time=${signature.signTime}&q-header-list=content-length;content-type;host&q-url-param-list=&q-signature=${signature.signature}`,
95+
contentType: generateContentType(fileName),
96+
contentLength: image.byteLength,
8397
'User-Agent': `PicGo;${version};null;null`
8498
},
8599
body: image,
@@ -100,14 +114,14 @@ const handle = async (ctx: IPicGo): Promise<IPicGo | boolean> => {
100114
const useV4 = !tcYunOptions.version || tcYunOptions.version === 'v4'
101115
for (const img of imgList) {
102116
if (img.fileName && img.buffer) {
103-
const signature = generateSignature(tcYunOptions, img.fileName)
104-
if (!signature) {
105-
return false
106-
}
107117
let image = img.buffer
108118
if (!image && img.base64Image) {
109119
image = Buffer.from(img.base64Image, 'base64')
110120
}
121+
const signature = generateSignature(tcYunOptions, img.fileName, generateContentType(img.fileName), image.byteLength)
122+
if (!signature) {
123+
return false
124+
}
111125
const options = postOptions(tcYunOptions, img.fileName, signature, image, ctx.GUI_VERSION || ctx.VERSION)
112126
const res = await ctx.request(options)
113127
.then((res: any) => res)

0 commit comments

Comments
 (0)