Skip to content

Dev/2.14.0 #208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,14 @@ declare namespace COS {
/** 是否开启长链接,默认开启 */
KeepAlive?: boolean;
Ip?: string;
/** 是否严格校验 HTTPS 证书,默认 true */
StrictSsl?: boolean;
/** 自定义 UserAgent */
UserAgent?: string;
/** 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true */
ForceSignHost?: boolean;
AutoSwitchHost?: boolean;
ObjectKeySimplifyCheck?: boolean;
/** 自定义拷贝源解析器 */
CopySourceParser?: null | CopySourceParserFunction;
/** 获取签名的回调方法,如果没有 SecretId、SecretKey 时,必选 */
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cos-nodejs-sdk-v5",
"version": "2.13.5",
"version": "2.14.0",
"description": "cos nodejs sdk v5",
"main": "index.js",
"types": "index.d.ts",
Expand Down
12 changes: 10 additions & 2 deletions sdk/advance.js
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,14 @@ function copySliceItem(params, callback) {

// 分片下载文件
function downloadFile(params, callback) {
if (this.options.ObjectKeySimplifyCheck) {
// getObject 的 Key 需要格式化,避免调用成 getBucket
var formatKey = util.simplifyPath(params.Key);
if (formatKey === '/') {
callback(util.error(new Error('The Getobject Key is illegal')));
return;
}
}
var self = this;
var TaskId = params.TaskId || util.uuid();
var Bucket = params.Bucket;
Expand Down Expand Up @@ -1434,8 +1442,8 @@ function downloadFile(params, callback) {
if (err) return ep.emit('error', err);

// 获取文件大小
FileSize = params.FileSize = parseInt(data.headers['content-length']);
if (FileSize === undefined || !FileSize) {
FileSize = params.FileSize = data.headers['content-length'] ? parseInt(data.headers['content-length']) : undefined;
if (FileSize === undefined) {
callback(
util.error(
new Error(
Expand Down
8 changes: 8 additions & 0 deletions sdk/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,14 @@ function listObjectVersions(params, callback) {
* @param {Object} data 为对应的 object 数据,包括 body 和 headers
*/
function getObject(params, callback) {
if (this.options.ObjectKeySimplifyCheck) {
// getObject 的 Key 需要格式化,避免调用成 getBucket
var formatKey = util.simplifyPath(params.Key);
if (formatKey === '/') {
callback(util.error(new Error('The Getobject Key is illegal')));
return;
}
}
var reqParams = params.Query || {};
var reqParamsStr = params.QueryString || '';

Expand Down
1 change: 1 addition & 0 deletions sdk/cos.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ var defaultOptions = {
ForceSignHost: true, // 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true
AutoSwitchHost: true,
CopySourceParser: null, // 自定义拷贝源解析器
ObjectKeySimplifyCheck: true, // 开启合并校验 getObject Key
// 动态秘钥,优先级Credentials > SecretId/SecretKey。注意Cred内是小写的secretId、secretKey
Credentials: {
secretId: '',
Expand Down
21 changes: 19 additions & 2 deletions sdk/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,9 @@ var apiWrapper = function (apiName, apiFn) {
delete params.AppId;
}
}
// 如果 Key 是 / 开头,强制去掉第一个 /
if (!self.options.UseRawKey && params.Key && params.Key.substr(0, 1) === '/') {
// 除了下列 api,如果 Key 是 / 开头,强制去掉第一个 /
var dontRemoveApi = ['sliceUploadFile', 'uploadFile', 'downloadFile', 'sliceCopyFile'];
if (!self.options.UseRawKey && params.Key && params.Key.substr(0, 1) === '/' && !dontRemoveApi.includes(apiName)) {
params.Key = params.Key.substr(1);
}
}
Expand Down Expand Up @@ -736,6 +737,21 @@ var encodeBase64 = function (str, safe) {
return base64Str;
};

var simplifyPath = function (path) {
const names = path.split('/');
const stack = [];
for (const name of names) {
if (name === '..') {
if (stack.length) {
stack.pop();
}
} else if (name.length && name !== '.') {
stack.push(name);
}
}
return '/' + stack.join('/');
};

var util = {
noop: noop,
formatParams: formatParams,
Expand Down Expand Up @@ -772,6 +788,7 @@ var util = {
isCIHost: isCIHost,
getSourceParams: getSourceParams,
encodeBase64: encodeBase64,
simplifyPath: simplifyPath,
};

module.exports = util;
198 changes: 197 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6069,6 +6069,197 @@ group('sliceUploadFile() 续传', function () {
});
});


group('getObject() 默认开启合并 Key 校验', function () {
function getObjectErrorKey(Key, done) {
cos.getObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key,
},
function (err, data) {
assert.ok(err.message === 'The Getobject Key is illegal');
done();
}
);
}
test('getObject() object The Getobject Key is illegal 1', function (done) {
getObjectErrorKey('///////', done);
});
test('getObject() object The Getobject Key is illegal 2', function (done) {
getObjectErrorKey('/abc/../', done);
});
test('getObject() object The Getobject Key is illegal 3', function (done) {
getObjectErrorKey('/./', done);
});
test('getObject() object The Getobject Key is illegal 4', function (done) {
getObjectErrorKey('///abc/.//def//../../', done);
});
test('getObject() object The Getobject Key is illegal 5', function (done) {
getObjectErrorKey('/././///abc/.//def//../../', done);
});
});

group('getObject() 手动关闭合并 Key 校验', function () {
var cos = new COS({
// 必选参数
SecretId: config.SecretId,
SecretKey: config.SecretKey,
Protocol: 'http',
ObjectKeySimplifyCheck: false,
});
function putObjectAndGetObject(Key, done) {
const Body = Key;
cos.putObject({
Bucket: config.Bucket,
Region: config.Region,
Key,
Body,
}, function(err, data) {
if (err) {
done(err);
} else {
cos.getObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key,
},
function (err, data) {
assert.ok(data.Body.toString() === Body);
done();
}
);
}
});
}
test('getObject() object The Getobject Key is illegal 1', function (done) {
// 会转成 getBucket
cos.getObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: '///////',
},
function (err, data) {
assert.ok(data.Body.toString().includes('ListBucketResult'));
done();
}
);
});
test('getObject() object The Getobject Key is illegal 2', function (done) {
putObjectAndGetObject('/abc/../', done);
});
test('getObject() object The Getobject Key is illegal 3', function (done) {
// 会转成 getBucket
cos.getObject(
{
Bucket: config.Bucket,
Region: config.Region,
Key: '/./',
},
function (err, data) {
assert.ok(data.Body.toString().includes('ListBucketResult'));
done();
}
);
});
test('getObject() object The Getobject Key is illegal 4', function (done) {
putObjectAndGetObject('///abc/.//def//../../', done);
});
test('getObject() object The Getobject Key is illegal 5', function (done) {
putObjectAndGetObject('/././///abc/.//def//../../', done);
});
});

group('downloadFile() 默认开启合并 Key 校验', function () {
function downloadFileErrorKey(Key, done) {
cos.downloadFile(
{
Bucket: config.Bucket,
Region: config.Region,
Key,
FilePath: './' + Key
},
function (err, data) {
assert.ok(err.message === 'The Getobject Key is illegal');
done();
}
);
}
test('downloadFile() object The Getobject Key is illegal 1', function (done) {
downloadFileErrorKey('///////', done);
});
test('downloadFile() object The Getobject Key is illegal 2', function (done) {
downloadFileErrorKey('/abc/../', done);
});
test('downloadFile() object The Getobject Key is illegal 3', function (done) {
downloadFileErrorKey('/./', done);
});
test('downloadFile() object The Getobject Key is illegal 4', function (done) {
downloadFileErrorKey('///abc/.//def//../../', done);
});
test('downloadFile() object The Getobject Key is illegal 5', function (done) {
downloadFileErrorKey('/././///abc/.//def//../../', done);
});
});

group('downloadFile() 手动关闭合并 Key 校验', function () {
var cos = new COS({
// 必选参数
SecretId: config.SecretId,
SecretKey: config.SecretKey,
Protocol: 'http',
ObjectKeySimplifyCheck: false,
});
function getObjectOrGetBucket(Key, hasEtag, done) {
const Body = Key;
cos.putObject({
Bucket: config.Bucket,
Region: config.Region,
Key,
Body,
}, function(err, data) {
if (err) {
done();
} else {
cos.downloadFile(
{
Bucket: config.Bucket,
Region: config.Region,
Key,
FilePath: './testFile'
},
function (err, data) {
const isGetBucket = data.ETag === '';
const isGetObject = data.ETag !== '';
const ok = hasEtag ? isGetObject : isGetBucket;
fs.unlinkSync('./testFile');
assert.ok(ok);
done();
}
);
}
});
}
test('downloadFile() object The Getobject Key is illegal 1', function (done) {
getObjectOrGetBucket('///////', false, done);
});
test('downloadFile() object The Getobject Key is illegal 2', function (done) {
getObjectOrGetBucket('/abc/../', true, done);
});
test('downloadFile() object The Getobject Key is illegal 3', function (done) {
getObjectOrGetBucket('/./', false, done);
});
test('downloadFile() object The Getobject Key is illegal 4', function (done) {
getObjectOrGetBucket('///abc/.//def//../../', true, done);
});
test('downloadFile() object The Getobject Key is illegal 5', function (done) {
getObjectOrGetBucket('/././///abc/.//def//../../', true, done);
});
});

group('getStream() 流式下载 ECONNREFUSED 错误', function () {
test('getStream() 流式下载 ECONNREFUSED 错误', function (done, assert) {
cos.options.Domain = '127.0.0.1:12345';
Expand Down Expand Up @@ -6155,6 +6346,7 @@ group('downloadFile', function () {
});
test('downloadFile() fileSize=0', function (done, assert) {
var Key = '0b.zip';
var FilePath = './' + Key;
cos.downloadFile(
{
Bucket: config.Bucket, // Bucket 格式:test-1250000000
Expand All @@ -6167,7 +6359,8 @@ group('downloadFile', function () {
TaskId: '123', // 可以自己生成TaskId,用于取消下载
},
function (err, data) {
assert.ok(err);
fs.unlinkSync(FilePath);
assert.ok(!err);
done();
}
);
Expand Down Expand Up @@ -6198,6 +6391,7 @@ group('downloadFile', function () {
TaskId: '123', // 可以自己生成TaskId,用于取消下载
},
function (err, data) {
fs.unlinkSync(filePath);
assert.ok(!err);
done();
}
Expand Down Expand Up @@ -6238,6 +6432,7 @@ group('downloadFile', function () {
TaskId: '123', // 可以自己生成TaskId,用于取消下载
},
function (err, data) {
fs.unlinkSync(filePath);
assert.ok(!err);
done();
}
Expand Down Expand Up @@ -6345,6 +6540,7 @@ group('downloadFile', function () {
onProgress: function (progressData) {
if (progressData.percent >= 0.1) {
cos.emit('inner-kill-task', { TaskId: 'downloadFile-123' });
fs.unlinkSync(filePath);
assert.ok(1);
done();
}
Expand Down