Skip to content

Commit

Permalink
Dev/1.6.0 (#202)
Browse files Browse the repository at this point in the history
feat
1、提升安全性:不再支持path-style
2、修复 uploadFile 未对参数 Key 进行校验
  • Loading branch information
livehigh authored Jan 22, 2024
1 parent 0271282 commit 586b43a
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 146 deletions.
20 changes: 20 additions & 0 deletions demo/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "cos-js-sdk-nextjs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"cos-js-sdk-v5": "^1.5.0",
"next": "^14.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
39 changes: 39 additions & 0 deletions demo/nextjs/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import COS from 'cos-js-sdk-v5';

// 初始化可参考 https://cloud.tencent.com/document/product/436/11459#.E5.BC.80.E5.A7.8B.E4.BD.BF.E7.94.A8
const cos = new COS({
SecretId: '',
SecretKey: '',
});

let selectedFile = null;

const handleFileChange = (event) => {
selectedFile = event.target.files[0];
};

const handleUpload = () => {
if (selectedFile) {
console.log('上传文件:', selectedFile);
cos.uploadFile({
Bucket: 'examplebucket-1250000000', /* 填入您自己的存储桶,必须字段 */
Region: 'COS_REGION', /* 存储桶所在地域,例如ap-beijing,必须字段 */
Key: selectedFile.name, /* 存储在桶里的对象键(例如1.jpg,a/b/test.txt),必须字段 */
Body: selectedFile, /* 必须,上传文件对象,可以是input[type="file"]标签选择本地文件后得到的file对象 */
SliceSize: 1024 * 1024 * 5, /* 触发分块上传的阈值,超过5MB使用分块上传,非必须 */
onProgress: function (progressData) { /* 非必须 */
console.log(JSON.stringify(progressData));
},
}, function (err, data) {
console.log(err || data);
});

} else {
console.log('请选择一个文件');
}
};

export default () => <div>
<input type="file" onChange={handleFileChange} />
<button onClick={handleUpload}>上传</button>
</div>
95 changes: 82 additions & 13 deletions dist/cos-js-sdk-v5.js
Original file line number Diff line number Diff line change
Expand Up @@ -8628,7 +8628,7 @@ module.exports = function(module) {
/*! exports provided: name, version, description, main, types, scripts, repository, keywords, author, license, bugs, homepage, dependencies, devDependencies, default */
/***/ (function(module) {

module.exports = JSON.parse("{\"name\":\"cos-js-sdk-v5\",\"version\":\"1.5.0\",\"description\":\"JavaScript SDK for [腾讯云对象存储](https://cloud.tencent.com/product/cos)\",\"main\":\"dist/cos-js-sdk-v5.js\",\"types\":\"index.d.ts\",\"scripts\":{\"prettier\":\"prettier --write src demo/demo.js demo/CIDemos/*.js test/test.js server/sts.js index.d.ts\",\"server\":\"node server/sts.js\",\"dev\":\"cross-env NODE_ENV=development webpack -w --mode=development\",\"build\":\"cross-env NODE_ENV=production webpack --mode=production\",\"cos-auth.min.js\":\"uglifyjs ./demo/common/cos-auth.js -o ./demo/common/cos-auth.min.js -c -m\",\"test\":\"jest --runInBand --coverage\"},\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/tencentyun/cos-js-sdk-v5.git\"},\"keywords\":[],\"author\":\"carsonxu\",\"license\":\"ISC\",\"bugs\":{\"url\":\"https://github.com/tencentyun/cos-js-sdk-v5/issues\"},\"homepage\":\"https://github.com/tencentyun/cos-js-sdk-v5#readme\",\"dependencies\":{\"@xmldom/xmldom\":\"^0.8.6\"},\"devDependencies\":{\"@babel/core\":\"7.17.9\",\"@babel/plugin-transform-runtime\":\"7.18.10\",\"@babel/preset-env\":\"7.16.11\",\"babel-loader\":\"8.2.5\",\"body-parser\":\"^1.18.3\",\"cross-env\":\"^5.2.0\",\"express\":\"^4.16.4\",\"jest\":\"^29.3.1\",\"jest-environment-jsdom\":\"^29.3.1\",\"prettier\":\"^3.0.1\",\"qcloud-cos-sts\":\"^3.0.2\",\"request\":\"^2.87.0\",\"terser-webpack-plugin\":\"4.2.3\",\"uglifyjs\":\"^2.4.11\",\"webpack\":\"4.46.0\",\"webpack-cli\":\"4.10.0\"}}");
module.exports = JSON.parse("{\"name\":\"cos-js-sdk-v5\",\"version\":\"1.6.0\",\"description\":\"JavaScript SDK for [腾讯云对象存储](https://cloud.tencent.com/product/cos)\",\"main\":\"dist/cos-js-sdk-v5.js\",\"types\":\"index.d.ts\",\"scripts\":{\"prettier\":\"prettier --write src demo/demo.js demo/CIDemos/*.js test/test.js server/sts.js lib/request.js index.d.ts\",\"server\":\"node server/sts.js\",\"dev\":\"cross-env NODE_ENV=development webpack -w --mode=development\",\"build\":\"cross-env NODE_ENV=production webpack --mode=production\",\"cos-auth.min.js\":\"uglifyjs ./demo/common/cos-auth.js -o ./demo/common/cos-auth.min.js -c -m\",\"test\":\"jest --runInBand --coverage\"},\"repository\":{\"type\":\"git\",\"url\":\"git+https://github.com/tencentyun/cos-js-sdk-v5.git\"},\"keywords\":[],\"author\":\"carsonxu\",\"license\":\"ISC\",\"bugs\":{\"url\":\"https://github.com/tencentyun/cos-js-sdk-v5/issues\"},\"homepage\":\"https://github.com/tencentyun/cos-js-sdk-v5#readme\",\"dependencies\":{\"@xmldom/xmldom\":\"^0.8.6\"},\"devDependencies\":{\"@babel/core\":\"7.17.9\",\"@babel/plugin-transform-runtime\":\"7.18.10\",\"@babel/preset-env\":\"7.16.11\",\"babel-loader\":\"8.2.5\",\"body-parser\":\"^1.18.3\",\"cross-env\":\"^5.2.0\",\"express\":\"^4.16.4\",\"jest\":\"^29.3.1\",\"jest-environment-jsdom\":\"^29.3.1\",\"prettier\":\"^3.0.1\",\"qcloud-cos-sts\":\"^3.0.2\",\"request\":\"^2.87.0\",\"terser-webpack-plugin\":\"4.2.3\",\"uglifyjs\":\"^2.4.11\",\"webpack\":\"4.46.0\",\"webpack-cli\":\"4.10.0\"}}");

/***/ }),

Expand Down Expand Up @@ -12780,7 +12780,7 @@ function multipartComplete(params, callback) {
Part: Parts
}
});
// CSP/ceph CompleteMultipartUpload 接口 body 写死了限制 1MB,这里醉倒 10000 片时,xml 字符串去掉空格853KB
// CSP/ceph CompleteMultipartUpload 接口 body 写死了限制 1MB,这里最多 10000 片时,xml 字符串去掉空格853KB
xml = xml.replace(/\n\s*/g, '');
var headers = params.Headers;
headers['Content-Type'] = 'application/xml';
Expand Down Expand Up @@ -13406,7 +13406,8 @@ function getAuthorizationAsync(params, callback) {
SecurityToken: StsData.SecurityToken || StsData.XCosSecurityToken || '',
Token: StsData.Token || '',
ClientIP: StsData.ClientIP || '',
ClientUA: StsData.ClientUA || ''
ClientUA: StsData.ClientUA || '',
SignFrom: 'client'
};
cb(null, AuthData);
};
Expand Down Expand Up @@ -13507,7 +13508,8 @@ function getAuthorizationAsync(params, callback) {
});
var AuthData = {
Authorization: Authorization,
SecurityToken: self.options.SecurityToken || self.options.XCosSecurityToken
SecurityToken: self.options.SecurityToken || self.options.XCosSecurityToken,
SignFrom: 'client'
};
cb(null, AuthData);
return AuthData;
Expand All @@ -13516,10 +13518,12 @@ function getAuthorizationAsync(params, callback) {
return '';
}

// 调整时间偏差
// 判断当前请求出错时能否重试
function allowRetry(err) {
var allowRetry = false;
var self = this;
var canRetry = false;
var isTimeError = false;
var networkError = false;
var serverDate = err.headers && (err.headers.date || err.headers.Date) || err.error && err.error.ServerTime;
try {
var errorCode = err.error.Code;
Expand All @@ -13529,18 +13533,46 @@ function allowRetry(err) {
}
} catch (e) {}
if (err) {
// 调整时间偏差
if (isTimeError && serverDate) {
var serverTime = Date.parse(serverDate);
if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) {
console.error('error: Local time is too skewed.');
this.options.SystemClockOffset = serverTime - Date.now();
allowRetry = true;
canRetry = true;
}
} else if (Math.floor(err.statusCode / 100) === 5) {
allowRetry = true;
canRetry = true;
} else if (err.message === 'CORS blocked or network error') {
// 跨域/网络错误都包含在内
networkError = true;
canRetry = self.options.AutoSwitchHost;
}
}
return allowRetry;
return {
canRetry: canRetry,
networkError: networkError
};
}

/**
* requestUrl:请求的url,用于判断是否cos主域名,true才切
* clientCalcSign:是否客户端计算签名,服务端返回的签名不能切,true才切
* networkError:是否未知网络错误,true才切
* */
function canSwitchHost(_ref) {
var requestUrl = _ref.requestUrl,
clientCalcSign = _ref.clientCalcSign,
networkError = _ref.networkError;
if (!this.options.AutoSwitchHost) return false;
if (!requestUrl) return false;
if (!clientCalcSign) return false;
if (!networkError) return false;
var commonReg = /^https?:\/\/[^\/]*\.cos\.[^\/]*\.myqcloud\.com(\/.*)?$/;
var accelerateReg = /^https?:\/\/[^\/]*\.cos\.accelerate\.myqcloud\.com(\/.*)?$/;
// 当前域名是cos主域名才切换
var isCommonCosHost = commonReg.test(requestUrl) && !accelerateReg.test(requestUrl);
return isCommonCosHost;
}

// 获取签名并发起请求
Expand All @@ -13560,6 +13592,11 @@ function submitRequest(params, callback) {
params.qs && (params.qs = util.clearKey(params.qs));
var Query = util.clone(params.qs);
params.action && (Query[params.action] = '');

/**
* 手动传params.SignHost的场景:cos.getService、cos.getObjectUrl
* 手动传Url的场景:cos.request
*/
var paramsUrl = params.url || params.Url;
var SignHost = params.SignHost || getSignHost.call(this, {
Bucket: params.Bucket,
Expand All @@ -13573,6 +13610,10 @@ function submitRequest(params, callback) {
signStartTime: new Date().getTime(),
retryTimes: tryTimes - 1
});
if (params.SwitchHost) {
// 更换要签的host
SignHost = SignHost.replace(/myqcloud.com/, 'tencentcos.cn');
}
getAuthorizationAsync.call(self, {
Bucket: params.Bucket || '',
Region: params.Region || '',
Expand All @@ -13584,7 +13625,8 @@ function submitRequest(params, callback) {
Action: params.Action,
ResourceKey: params.ResourceKey,
Scope: params.Scope,
ForceSignHost: self.options.ForceSignHost
ForceSignHost: self.options.ForceSignHost,
SwitchHost: params.SwitchHost
}, function (err, AuthData) {
if (err) {
callback(err);
Expand All @@ -13599,7 +13641,14 @@ function submitRequest(params, callback) {
tracker && tracker.setParams({
httpEndTime: new Date().getTime()
});
if (err && tryTimes < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) {
var canRetry = false;
var networkError = false;
if (err) {
var info = allowRetry.call(self, err);
canRetry = info.canRetry || oldClockOffset !== self.options.SystemClockOffset;
networkError = info.networkError;
}
if (err && tryTimes < 2 && canRetry) {
if (params.headers) {
delete params.headers.Authorization;
delete params.headers['token'];
Expand All @@ -13608,6 +13657,13 @@ function submitRequest(params, callback) {
params.headers['x-cos-security-token'] && delete params.headers['x-cos-security-token'];
params.headers['x-ci-security-token'] && delete params.headers['x-ci-security-token'];
}
// 进入重试逻辑时 需判断是否需要切换cos备用域名
var switchHost = canSwitchHost.call(self, {
requestUrl: (err === null || err === void 0 ? void 0 : err.url) || '',
clientCalcSign: AuthData.SignFrom === 'client',
networkError: networkError
});
params.SwitchHost = switchHost;
next(tryTimes + 1);
} else {
callback(err, data);
Expand Down Expand Up @@ -13643,6 +13699,10 @@ function _submitRequest(params, callback) {
region: region,
object: object
});
if (params.SwitchHost) {
// 更换请求的url
url = url.replace(/myqcloud.com/, 'tencentcos.cn');
}
if (params.action) {
// 已知问题,某些版本的qq会对url自动拼接(比如/upload被拼接成/upload=(null))导致签名错误,这里做下兼容。
url = url + '?' + (util.isIOS_QQ ? "".concat(params.action, "=") : params.action);
Expand Down Expand Up @@ -13745,6 +13805,8 @@ function _submitRequest(params, callback) {
response && response.statusCode && (attrs.statusCode = response.statusCode);
response && response.headers && (attrs.headers = response.headers);
if (err) {
opt.url && (attrs.url = opt.url);
opt.method && (attrs.method = opt.method);
err = util.extend(err || {}, attrs);
callback(err, null);
} else {
Expand Down Expand Up @@ -13982,7 +14044,9 @@ var defaultOptions = {
// 上报时是否对每个分块上传做单独上报
TrackerDelay: 5000,
// 周期性上报,单位毫秒。0代表实时上报
CustomId: '' // 自定义上报id
CustomId: '',
// 自定义上报id
AutoSwitchHost: true
};

// 对外暴露的类
Expand All @@ -14009,9 +14073,14 @@ var COS = function COS(options) {
console.error('error: SecretKey format is incorrect. Please check');
}
if (util.isNode()) {
console.log('Tip: Next.js、Nuxt.js 等服务端渲染技术可正常使用JavaScript SDK,请忽略下方 nodejs 环境警告');
console.warn('warning: cos-js-sdk-v5 不支持 nodejs 环境使用,请改用 cos-nodejs-sdk-v5,参考文档: https://cloud.tencent.com/document/product/436/8629');
console.warn('warning: cos-js-sdk-v5 does not support nodejs environment. Please use cos-nodejs-sdk-v5 instead. See: https://cloud.tencent.com/document/product/436/8629');
}
if (this.options.ForcePathStyle) {
console.warn('cos-js-sdk-v5不再支持使用path-style,仅支持使用virtual-hosted-style,参考文档:https://cloud.tencent.com/document/product/436/96243');
throw new Error('ForcePathStyle is not supported');
}
event.init(this);
task.init(this);
};
Expand Down Expand Up @@ -15270,7 +15339,7 @@ var hasMissingParams = function hasMissingParams(apiName, params) {
if (apiName.indexOf('Bucket') > -1 || apiName === 'deleteMultipleObject' || apiName === 'multipartList' || apiName === 'listObjectVersions') {
if (checkBucket && !Bucket) return 'Bucket';
if (checkRegion && !Region) return 'Region';
} else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask') {
} else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask' || apiName === 'uploadFile') {
if (checkBucket && !Bucket) return 'Bucket';
if (checkRegion && !Region) return 'Region';
if (!Key) return 'Key';
Expand Down
2 changes: 1 addition & 1 deletion dist/cos-js-sdk-v5.min.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ declare namespace COS {
DeepTracker?: boolean;
TrackerDelay?: number;
CustomId?: string;
AutoSwitchHost?: boolean;
/** 链路上报 */
/** 获取签名的回调方法,如果没有 SecretId、SecretKey 时,必选 */
getAuthorization?: (
Expand Down Expand Up @@ -298,6 +299,10 @@ declare namespace COS {
message: string;
/** 兼容老的错误信息字段,不建议使用,可能是参数错误、客户端出错、或服务端返回的错误 */
error: string | Error | { Code: string; Message: string };
/** 当前请求的Url */
url: string;
/** 当前请求的method */
method: string;
}
/** 回调的错误格式,其中服务端返回错误码可查看 @see https://cloud.tencent.com/document/product/436/7730 */
type CosError = null | CosSdkError;
Expand Down
Loading

0 comments on commit 586b43a

Please sign in to comment.