Skip to content

Commit 5717876

Browse files
authored
Dev/2.14.0 (#208)
feat: getObject 新增 Key 格式化
1 parent 6938488 commit 5717876

File tree

7 files changed

+241
-6
lines changed

7 files changed

+241
-6
lines changed

index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,14 @@ declare namespace COS {
198198
/** 是否开启长链接,默认开启 */
199199
KeepAlive?: boolean;
200200
Ip?: string;
201+
/** 是否严格校验 HTTPS 证书,默认 true */
202+
StrictSsl?: boolean;
203+
/** 自定义 UserAgent */
204+
UserAgent?: string;
201205
/** 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true */
202206
ForceSignHost?: boolean;
203207
AutoSwitchHost?: boolean;
208+
ObjectKeySimplifyCheck?: boolean;
204209
/** 自定义拷贝源解析器 */
205210
CopySourceParser?: null | CopySourceParserFunction;
206211
/** 获取签名的回调方法,如果没有 SecretId、SecretKey 时,必选 */

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cos-nodejs-sdk-v5",
3-
"version": "2.13.5",
3+
"version": "2.14.0",
44
"description": "cos nodejs sdk v5",
55
"main": "index.js",
66
"types": "index.d.ts",

sdk/advance.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,14 @@ function copySliceItem(params, callback) {
14011401

14021402
// 分片下载文件
14031403
function downloadFile(params, callback) {
1404+
if (this.options.ObjectKeySimplifyCheck) {
1405+
// getObject 的 Key 需要格式化,避免调用成 getBucket
1406+
var formatKey = util.simplifyPath(params.Key);
1407+
if (formatKey === '/') {
1408+
callback(util.error(new Error('The Getobject Key is illegal')));
1409+
return;
1410+
}
1411+
}
14041412
var self = this;
14051413
var TaskId = params.TaskId || util.uuid();
14061414
var Bucket = params.Bucket;
@@ -1434,8 +1442,8 @@ function downloadFile(params, callback) {
14341442
if (err) return ep.emit('error', err);
14351443

14361444
// 获取文件大小
1437-
FileSize = params.FileSize = parseInt(data.headers['content-length']);
1438-
if (FileSize === undefined || !FileSize) {
1445+
FileSize = params.FileSize = data.headers['content-length'] ? parseInt(data.headers['content-length']) : undefined;
1446+
if (FileSize === undefined) {
14391447
callback(
14401448
util.error(
14411449
new Error(

sdk/base.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,14 @@ function listObjectVersions(params, callback) {
20612061
* @param {Object} data 为对应的 object 数据,包括 body 和 headers
20622062
*/
20632063
function getObject(params, callback) {
2064+
if (this.options.ObjectKeySimplifyCheck) {
2065+
// getObject 的 Key 需要格式化,避免调用成 getBucket
2066+
var formatKey = util.simplifyPath(params.Key);
2067+
if (formatKey === '/') {
2068+
callback(util.error(new Error('The Getobject Key is illegal')));
2069+
return;
2070+
}
2071+
}
20642072
var reqParams = params.Query || {};
20652073
var reqParamsStr = params.QueryString || '';
20662074

sdk/cos.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ var defaultOptions = {
4646
ForceSignHost: true, // 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true
4747
AutoSwitchHost: true,
4848
CopySourceParser: null, // 自定义拷贝源解析器
49+
ObjectKeySimplifyCheck: true, // 开启合并校验 getObject Key
4950
// 动态秘钥,优先级Credentials > SecretId/SecretKey。注意Cred内是小写的secretId、secretKey
5051
Credentials: {
5152
secretId: '',

sdk/util.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,9 @@ var apiWrapper = function (apiName, apiFn) {
527527
delete params.AppId;
528528
}
529529
}
530-
// 如果 Key 是 / 开头,强制去掉第一个 /
531-
if (!self.options.UseRawKey && params.Key && params.Key.substr(0, 1) === '/') {
530+
// 除了下列 api,如果 Key 是 / 开头,强制去掉第一个 /
531+
var dontRemoveApi = ['sliceUploadFile', 'uploadFile', 'downloadFile', 'sliceCopyFile'];
532+
if (!self.options.UseRawKey && params.Key && params.Key.substr(0, 1) === '/' && !dontRemoveApi.includes(apiName)) {
532533
params.Key = params.Key.substr(1);
533534
}
534535
}
@@ -736,6 +737,21 @@ var encodeBase64 = function (str, safe) {
736737
return base64Str;
737738
};
738739

740+
var simplifyPath = function (path) {
741+
const names = path.split('/');
742+
const stack = [];
743+
for (const name of names) {
744+
if (name === '..') {
745+
if (stack.length) {
746+
stack.pop();
747+
}
748+
} else if (name.length && name !== '.') {
749+
stack.push(name);
750+
}
751+
}
752+
return '/' + stack.join('/');
753+
};
754+
739755
var util = {
740756
noop: noop,
741757
formatParams: formatParams,
@@ -772,6 +788,7 @@ var util = {
772788
isCIHost: isCIHost,
773789
getSourceParams: getSourceParams,
774790
encodeBase64: encodeBase64,
791+
simplifyPath: simplifyPath,
775792
};
776793

777794
module.exports = util;

test/test.js

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6069,6 +6069,197 @@ group('sliceUploadFile() 续传', function () {
60696069
});
60706070
});
60716071

6072+
6073+
group('getObject() 默认开启合并 Key 校验', function () {
6074+
function getObjectErrorKey(Key, done) {
6075+
cos.getObject(
6076+
{
6077+
Bucket: config.Bucket,
6078+
Region: config.Region,
6079+
Key,
6080+
},
6081+
function (err, data) {
6082+
assert.ok(err.message === 'The Getobject Key is illegal');
6083+
done();
6084+
}
6085+
);
6086+
}
6087+
test('getObject() object The Getobject Key is illegal 1', function (done) {
6088+
getObjectErrorKey('///////', done);
6089+
});
6090+
test('getObject() object The Getobject Key is illegal 2', function (done) {
6091+
getObjectErrorKey('/abc/../', done);
6092+
});
6093+
test('getObject() object The Getobject Key is illegal 3', function (done) {
6094+
getObjectErrorKey('/./', done);
6095+
});
6096+
test('getObject() object The Getobject Key is illegal 4', function (done) {
6097+
getObjectErrorKey('///abc/.//def//../../', done);
6098+
});
6099+
test('getObject() object The Getobject Key is illegal 5', function (done) {
6100+
getObjectErrorKey('/././///abc/.//def//../../', done);
6101+
});
6102+
});
6103+
6104+
group('getObject() 手动关闭合并 Key 校验', function () {
6105+
var cos = new COS({
6106+
// 必选参数
6107+
SecretId: config.SecretId,
6108+
SecretKey: config.SecretKey,
6109+
Protocol: 'http',
6110+
ObjectKeySimplifyCheck: false,
6111+
});
6112+
function putObjectAndGetObject(Key, done) {
6113+
const Body = Key;
6114+
cos.putObject({
6115+
Bucket: config.Bucket,
6116+
Region: config.Region,
6117+
Key,
6118+
Body,
6119+
}, function(err, data) {
6120+
if (err) {
6121+
done(err);
6122+
} else {
6123+
cos.getObject(
6124+
{
6125+
Bucket: config.Bucket,
6126+
Region: config.Region,
6127+
Key,
6128+
},
6129+
function (err, data) {
6130+
assert.ok(data.Body.toString() === Body);
6131+
done();
6132+
}
6133+
);
6134+
}
6135+
});
6136+
}
6137+
test('getObject() object The Getobject Key is illegal 1', function (done) {
6138+
// 会转成 getBucket
6139+
cos.getObject(
6140+
{
6141+
Bucket: config.Bucket,
6142+
Region: config.Region,
6143+
Key: '///////',
6144+
},
6145+
function (err, data) {
6146+
assert.ok(data.Body.toString().includes('ListBucketResult'));
6147+
done();
6148+
}
6149+
);
6150+
});
6151+
test('getObject() object The Getobject Key is illegal 2', function (done) {
6152+
putObjectAndGetObject('/abc/../', done);
6153+
});
6154+
test('getObject() object The Getobject Key is illegal 3', function (done) {
6155+
// 会转成 getBucket
6156+
cos.getObject(
6157+
{
6158+
Bucket: config.Bucket,
6159+
Region: config.Region,
6160+
Key: '/./',
6161+
},
6162+
function (err, data) {
6163+
assert.ok(data.Body.toString().includes('ListBucketResult'));
6164+
done();
6165+
}
6166+
);
6167+
});
6168+
test('getObject() object The Getobject Key is illegal 4', function (done) {
6169+
putObjectAndGetObject('///abc/.//def//../../', done);
6170+
});
6171+
test('getObject() object The Getobject Key is illegal 5', function (done) {
6172+
putObjectAndGetObject('/././///abc/.//def//../../', done);
6173+
});
6174+
});
6175+
6176+
group('downloadFile() 默认开启合并 Key 校验', function () {
6177+
function downloadFileErrorKey(Key, done) {
6178+
cos.downloadFile(
6179+
{
6180+
Bucket: config.Bucket,
6181+
Region: config.Region,
6182+
Key,
6183+
FilePath: './' + Key
6184+
},
6185+
function (err, data) {
6186+
assert.ok(err.message === 'The Getobject Key is illegal');
6187+
done();
6188+
}
6189+
);
6190+
}
6191+
test('downloadFile() object The Getobject Key is illegal 1', function (done) {
6192+
downloadFileErrorKey('///////', done);
6193+
});
6194+
test('downloadFile() object The Getobject Key is illegal 2', function (done) {
6195+
downloadFileErrorKey('/abc/../', done);
6196+
});
6197+
test('downloadFile() object The Getobject Key is illegal 3', function (done) {
6198+
downloadFileErrorKey('/./', done);
6199+
});
6200+
test('downloadFile() object The Getobject Key is illegal 4', function (done) {
6201+
downloadFileErrorKey('///abc/.//def//../../', done);
6202+
});
6203+
test('downloadFile() object The Getobject Key is illegal 5', function (done) {
6204+
downloadFileErrorKey('/././///abc/.//def//../../', done);
6205+
});
6206+
});
6207+
6208+
group('downloadFile() 手动关闭合并 Key 校验', function () {
6209+
var cos = new COS({
6210+
// 必选参数
6211+
SecretId: config.SecretId,
6212+
SecretKey: config.SecretKey,
6213+
Protocol: 'http',
6214+
ObjectKeySimplifyCheck: false,
6215+
});
6216+
function getObjectOrGetBucket(Key, hasEtag, done) {
6217+
const Body = Key;
6218+
cos.putObject({
6219+
Bucket: config.Bucket,
6220+
Region: config.Region,
6221+
Key,
6222+
Body,
6223+
}, function(err, data) {
6224+
if (err) {
6225+
done();
6226+
} else {
6227+
cos.downloadFile(
6228+
{
6229+
Bucket: config.Bucket,
6230+
Region: config.Region,
6231+
Key,
6232+
FilePath: './testFile'
6233+
},
6234+
function (err, data) {
6235+
const isGetBucket = data.ETag === '';
6236+
const isGetObject = data.ETag !== '';
6237+
const ok = hasEtag ? isGetObject : isGetBucket;
6238+
fs.unlinkSync('./testFile');
6239+
assert.ok(ok);
6240+
done();
6241+
}
6242+
);
6243+
}
6244+
});
6245+
}
6246+
test('downloadFile() object The Getobject Key is illegal 1', function (done) {
6247+
getObjectOrGetBucket('///////', false, done);
6248+
});
6249+
test('downloadFile() object The Getobject Key is illegal 2', function (done) {
6250+
getObjectOrGetBucket('/abc/../', true, done);
6251+
});
6252+
test('downloadFile() object The Getobject Key is illegal 3', function (done) {
6253+
getObjectOrGetBucket('/./', false, done);
6254+
});
6255+
test('downloadFile() object The Getobject Key is illegal 4', function (done) {
6256+
getObjectOrGetBucket('///abc/.//def//../../', true, done);
6257+
});
6258+
test('downloadFile() object The Getobject Key is illegal 5', function (done) {
6259+
getObjectOrGetBucket('/././///abc/.//def//../../', true, done);
6260+
});
6261+
});
6262+
60726263
group('getStream() 流式下载 ECONNREFUSED 错误', function () {
60736264
test('getStream() 流式下载 ECONNREFUSED 错误', function (done, assert) {
60746265
cos.options.Domain = '127.0.0.1:12345';
@@ -6155,6 +6346,7 @@ group('downloadFile', function () {
61556346
});
61566347
test('downloadFile() fileSize=0', function (done, assert) {
61576348
var Key = '0b.zip';
6349+
var FilePath = './' + Key;
61586350
cos.downloadFile(
61596351
{
61606352
Bucket: config.Bucket, // Bucket 格式:test-1250000000
@@ -6167,7 +6359,8 @@ group('downloadFile', function () {
61676359
TaskId: '123', // 可以自己生成TaskId,用于取消下载
61686360
},
61696361
function (err, data) {
6170-
assert.ok(err);
6362+
fs.unlinkSync(FilePath);
6363+
assert.ok(!err);
61716364
done();
61726365
}
61736366
);
@@ -6198,6 +6391,7 @@ group('downloadFile', function () {
61986391
TaskId: '123', // 可以自己生成TaskId,用于取消下载
61996392
},
62006393
function (err, data) {
6394+
fs.unlinkSync(filePath);
62016395
assert.ok(!err);
62026396
done();
62036397
}
@@ -6238,6 +6432,7 @@ group('downloadFile', function () {
62386432
TaskId: '123', // 可以自己生成TaskId,用于取消下载
62396433
},
62406434
function (err, data) {
6435+
fs.unlinkSync(filePath);
62416436
assert.ok(!err);
62426437
done();
62436438
}
@@ -6345,6 +6540,7 @@ group('downloadFile', function () {
63456540
onProgress: function (progressData) {
63466541
if (progressData.percent >= 0.1) {
63476542
cos.emit('inner-kill-task', { TaskId: 'downloadFile-123' });
6543+
fs.unlinkSync(filePath);
63486544
assert.ok(1);
63496545
done();
63506546
}

0 commit comments

Comments
 (0)