From 32c5c08e9a36493fc9e2f851ddada4f08c83c4ac Mon Sep 17 00:00:00 2001 From: carsonxu <459452372@qq.com> Date: Fri, 6 Aug 2021 22:25:26 +0800 Subject: [PATCH] =?UTF-8?q?Host=20=E5=8F=82=E4=B8=8E=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.d.ts | 8 ++++++++ package.json | 2 +- sdk/base.js | 47 ++++++++++++++++++++++++++++++++++++++++++++--- sdk/util.js | 3 +++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/index.d.ts b/index.d.ts index b4b1aa2..aeb5958 100644 --- a/index.d.ts +++ b/index.d.ts @@ -196,6 +196,10 @@ declare namespace COS { SecretId: string, /** 计算签名用的密钥 SecretKey,必选 */ SecretKey: string, + /** 请求的存储桶,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ + Bucket?: Bucket, + /** 请求的地域,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ + Region?: Region, /** 请求方法,可选 */ Method?: Method, /** 请求路径,最前面带 /,例如 /images/1.jpg,可选 */ @@ -1877,6 +1881,10 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ SecretId?: string, /** 计算签名用的密钥 SecretKey,如果不传会用实例本身的凭证,可选 */ SecretKey?: string, + /** 请求的存储桶,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ + Bucket?: Bucket, + /** 请求的地域,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ + Region?: Region, /** 请求方法 */ Method?: Method, /** 请求的对象键,最前面不带 /,例如 images/1.jpg */ diff --git a/package.json b/package.json index d182e75..1818068 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cos-nodejs-sdk-v5", - "version": "2.9.21", + "version": "2.10.0", "description": "cos nodejs sdk v5", "main": "index.js", "types": "index.d.ts", diff --git a/sdk/base.js b/sdk/base.js index 6b30a54..b3d431d 100644 --- a/sdk/base.js +++ b/sdk/base.js @@ -39,11 +39,17 @@ function getService(params, callback) { domain = protocol + '//service.cos.myqcloud.com'; } + var SignHost = ''; + var standardHost = region ? 'cos.' + region + '.myqcloud.com' : 'service.cos.myqcloud.com'; + var urlHost = domain.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); + if (standardHost === urlHost) SignHost = standardHost; + submitRequest.call(this, { Action: 'name/cos:GetService', url: domain, method: 'GET', headers: params.Headers, + SignHost: SignHost, }, function (err, data) { if (err) return callback(err); var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets @@ -3022,6 +3028,8 @@ function getAuth(params) { return util.getAuth({ SecretId: params.SecretId || this.options.SecretId || '', SecretKey: params.SecretKey || this.options.SecretKey || '', + Bucket: params.Bucket, + Region: params.Region, Method: params.Method, Key: params.Key, Query: params.Query, @@ -3067,12 +3075,19 @@ function getObjectUrl(params, callback) { var queryParamsStr = ''; if(params.Query){ - queryParamsStr += util.obj2str(params.Query); + queryParamsStr += util.obj2str(params.Query); } if(params.QueryString){ - queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; + queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; } + // 签名加上 Host,避免跨桶访问 + var SignHost = ''; + var standardHost = 'cos.' + params.Region + '.myqcloud.com'; + if (!self.options.ForcePathStyle) standardHost = params.Bucket + '.' + standardHost; + var urlHost = url.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); + if (standardHost === urlHost) SignHost = standardHost; + var syncUrl = url; if (params.Sign !== undefined && !params.Sign) { queryParamsStr && (syncUrl += '?' + queryParamsStr); @@ -3080,6 +3095,7 @@ function getObjectUrl(params, callback) { return syncUrl; } + var SignHost = getSignHost.call(this, {Bucket: params.Bucket, Region: params.Region, Url: url}); var AuthData = getAuthorizationAsync.call(this, { Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'), Bucket: params.Bucket || '', @@ -3088,7 +3104,8 @@ function getObjectUrl(params, callback) { Key: params.Key, Expires: params.Expires, Headers: params.Headers, - Query: params.Query + Query: params.Query, + SignHost: SignHost, }, function (err, AuthData) { if (!callback) return; if (err) { @@ -3234,14 +3251,36 @@ function getUrl(params) { return url; } +var getSignHost = function (opt) { + if (!opt.Bucket || !opt.Bucket) return ''; + var ps = this.options.ForcePathStyle; + var url = opt.Url || getUrl({ + ForcePathStyle: ps, + protocol: this.options.Protocol, + domain: this.options.Domain, + bucket: opt.Bucket, + region: opt.Region, + }); + var standardHost = (ps ? '' : opt.Bucket + '.') + 'cos.' + opt.Region + '.myqcloud.com'; + var urlHost = url.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); + if (standardHost === urlHost) return standardHost; + return ''; +} + // 异步获取签名 function getAuthorizationAsync(params, callback) { var headers = util.clone(params.Headers); + var headerHost = ''; util.each(headers, function (v, k) { (v === '' || ['content-type', 'cache-control', 'expires'].indexOf(k.toLowerCase()) > -1) && delete headers[k]; + if (k.toLowerCase() === 'host') headerHost = v; }); + // Host 加入签名计算 + if (!headerHost && params.SignHost) headers.Host = params.SignHost; + + // 获取凭证的回调,避免用户 callback 多次 var cbDone = false; var cb = function (err, AuthData) { @@ -3479,6 +3518,7 @@ function submitRequest(params, callback) { var Query = util.clone(params.qs); params.action && (Query[params.action] = ''); + var SignHost = params.SignHost || getSignHost.call(this, {Bucket: params.Bucket, Region: params.Region}); var next = function (tryTimes) { var oldClockOffset = self.options.SystemClockOffset; getAuthorizationAsync.call(self, { @@ -3488,6 +3528,7 @@ function submitRequest(params, callback) { Key: params.Key, Query: Query, Headers: params.headers, + SignHost: SignHost, Action: params.Action, ResourceKey: params.ResourceKey, Scope: params.Scope, diff --git a/sdk/util.js b/sdk/util.js index d171a92..ff1d7df 100644 --- a/sdk/util.js +++ b/sdk/util.js @@ -63,6 +63,9 @@ var getAuth = function (opt) { pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); } + // 如果有传入存储桶,那么签名默认加 Host 参与计算,避免跨桶访问 + if (!headers.Host && !headers.host && opt.Bucket && opt.Region) headers.Host = opt.Bucket + '.cos.' + opt.Region + '.myqcloud.com'; + if (!SecretId) throw new Error('missing param SecretId'); if (!SecretKey) throw new Error('missing param SecretKey');