Skip to content

Commit 1a05e80

Browse files
taotao7PeterRao
andauthored
feat: add asyncSignatureUrl method (#1057)
* feat: add asyncSignatureUrl method * chore: add asyncSignatureUrl warn message * feat: to resolve conversation * chore: optimized test case * chore: optimized test case * chore: chore: optimized test case * chore: the tag signatureUrl will be deprecated in the next version * chore: remove not use function checkBrowserEnv Co-authored-by: Undefined <peizerao@gmail.com>
1 parent e4d0e1f commit 1a05e80

File tree

8 files changed

+190
-63
lines changed

8 files changed

+190
-63
lines changed

README.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ All operation use es7 async/await to implement. All api is async function.
142142
- [.putMeta(name, meta[, options])](#putmetaname-meta-options)
143143
- [.deleteMulti(names[, options])](#deletemultinames-options)
144144
- [.signatureUrl(name[, options])](#signatureurlname-options)
145+
- [.asyncSignatureUrl(name[, options])](#signatureurlname-options)
145146
- [.putACL(name, acl[, options])](#putaclname-acl-options)
146147
- [.getACL(name[, options])](#getaclname-options)
147148
- [.restore(name[, options])](#restorename-options)
@@ -2636,6 +2637,83 @@ const url = store.signatureUrl('ossdemo.png', {
26362637
console.log(url);
26372638
```
26382639
2640+
### .asyncSignatureUrl(name[, options])
2641+
2642+
Basically the same as signatureUrl, if refreshSTSToken is configured asyncSignatureUrl will refresh stsToken
2643+
2644+
parameters:
2645+
2646+
- name {String} object name store on OSS
2647+
- [options] {Object} optional parameters
2648+
- [expires] {Number} after expires seconds, the url will become invalid, default is `1800`
2649+
- [method] {String} the HTTP method, default is 'GET'
2650+
- [Content-Type] {String} set the request content type
2651+
- [process] {String} image process params, will send with `x-oss-process`
2652+
e.g.: `{process: 'image/resize,w_200'}`
2653+
- [trafficLimit] {Number} traffic limit, range: `819200`~`838860800`.
2654+
- [subResource] {Object} additional signature parameters in url.
2655+
- [response] {Object} set the response headers for download
2656+
- [content-type] {String} set the response content type
2657+
- [content-disposition] {String} set the response content disposition
2658+
- [cache-control] {String} set the response cache control
2659+
- See more: <https://help.aliyun.com/document_detail/31980.html>
2660+
- [callback] {Object} set the callback for the operation
2661+
- url {String} set the url for callback
2662+
- [host] {String} set the host for callback
2663+
- body {String} set the body for callback
2664+
- [contentType] {String} set the type for body
2665+
- [customValue] {Object} set the custom value for callback,eg. {var1: value1,var2:value2}
2666+
2667+
Success will return signature url.
2668+
2669+
example:
2670+
2671+
- Get signature url for object
2672+
2673+
```js
2674+
const url = await store.asyncSignatureUrl('ossdemo.txt');
2675+
console.log(url);
2676+
// --------------------------------------------------
2677+
const url = await store.asyncSignatureUrl('ossdemo.txt', {
2678+
expires: 3600,
2679+
method: 'PUT'
2680+
});
2681+
console.log(url);
2682+
// put object with signatureUrl
2683+
// -------------------------------------------------
2684+
const url = await store.asyncSignatureUrl('ossdemo.txt', {
2685+
expires: 3600,
2686+
method: 'PUT',
2687+
'Content-Type': 'text/plain; charset=UTF-8',
2688+
});
2689+
console.log(url);
2690+
// --------------------------------------------------
2691+
const url = await store.asyncSignatureUrl('ossdemo.txt', {
2692+
expires: 3600,
2693+
response: {
2694+
'content-type': 'text/custom',
2695+
'content-disposition': 'attachment'
2696+
}
2697+
});
2698+
console.log(url);
2699+
// put operation
2700+
```
2701+
2702+
- Get a signature url for a processed image
2703+
2704+
```js
2705+
const url = await store.asyncSignatureUrl('ossdemo.png', {
2706+
process: 'image/resize,w_200'
2707+
});
2708+
console.log(url);
2709+
// --------------------------------------------------
2710+
const url = await store.asyncSignatureUrl('ossdemo.png', {
2711+
expires: 3600,
2712+
process: 'image/resize,w_200'
2713+
});
2714+
console.log(url);
2715+
```
2716+
26392717
### .putACL(name, acl[, options])
26402718
26412719
Set object's ACL.

lib/browser/object.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ merge(proto, require('../common/object/getObjectMeta'));
163163
merge(proto, require('../common/object/getObjectUrl'));
164164
merge(proto, require('../common/object/generateObjectUrl'));
165165
merge(proto, require('../common/object/signatureUrl'));
166+
merge(proto, require('../common/object/asyncSignatureUrl'));
166167

167168
proto.putMeta = async function putMeta(name, meta, options) {
168169
const copyResult = await this.copy(name, name, {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const urlutil = require('url');
2+
const utility = require('utility');
3+
const copy = require('copy-to');
4+
const signHelper = require('../../common/signUtils');
5+
const { isIP } = require('../utils/isIP');
6+
const { setSTSToken } = require('../utils/setSTSToken');
7+
const { isFunction } = require('../utils/isFunction');
8+
const proto = exports;
9+
10+
proto.asyncSignatureUrl = async function asyncSignatureUrl(name, options) {
11+
if (isIP(this.options.endpoint.hostname)) {
12+
throw new Error('can not get the object URL when endpoint is IP');
13+
}
14+
options = options || {};
15+
name = this._objectName(name);
16+
options.method = options.method || 'GET';
17+
const expires = utility.timestamp() + (options.expires || 1800);
18+
const params = {
19+
bucket: this.options.bucket,
20+
object: name
21+
};
22+
23+
const resource = this._getResource(params);
24+
25+
if (this.options.stsToken && isFunction(this.options.refreshSTSToken)) {
26+
await setSTSToken.call(this);
27+
}
28+
29+
if (this.options.stsToken) {
30+
options['security-token'] = this.options.stsToken;
31+
}
32+
33+
const signRes = signHelper._signatureForURL(this.options.accessKeySecret, options, resource, expires);
34+
35+
const url = urlutil.parse(this._getReqUrl(params));
36+
url.query = {
37+
OSSAccessKeyId: this.options.accessKeyId,
38+
Expires: expires,
39+
Signature: signRes.Signature
40+
};
41+
42+
copy(signRes.subResource).to(url.query);
43+
44+
return url.format();
45+
};

lib/common/object/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ merge(proto, require('./getAsyncFetch'));
2222
merge(proto, require('./generateObjectUrl'));
2323
merge(proto, require('./getObjectUrl'));
2424
merge(proto, require('./signatureUrl'));
25-
25+
merge(proto, require('./asyncSignatureUrl'));

lib/common/object/signatureUrl.js

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@ const utility = require('utility');
33
const copy = require('copy-to');
44
const signHelper = require('../../common/signUtils');
55
const { isIP } = require('../utils/isIP');
6-
const { isFunction } = require('../../common/utils/isFunction');
7-
const { checkCredentials } = require('../utils/setSTSToken');
8-
const { formatObjKey } = require('../utils/formatObjKey');
6+
97
const proto = exports;
108

9+
/**
10+
* signatureUrl
11+
* @deprecated will be deprecated in 7.x
12+
* @param {String} name object name
13+
* @param {Object} options options
14+
*/
1115
proto.signatureUrl = function signatureUrl(name, options) {
1216
if (isIP(this.options.endpoint.hostname)) {
1317
throw new Error('can not get the object URL when endpoint is IP');
@@ -23,22 +27,6 @@ proto.signatureUrl = function signatureUrl(name, options) {
2327

2428
const resource = this._getResource(params);
2529

26-
if (this.options.stsToken && isFunction(this.options.refreshSTSToken)) {
27-
const now = new Date();
28-
if (this.stsTokenFreshTime >= this.options.refreshSTSTokenInterval) {
29-
this.stsTokenFreshTime = now;
30-
this.options.refreshSTSToken().then(r => {
31-
const credentials = formatObjKey(r, 'firstLowerCase');
32-
if (credentials.securityToken) {
33-
credentials.stsToken = credentials.securityToken;
34-
}
35-
checkCredentials(credentials);
36-
Object.assign(this.options, credentials);
37-
});
38-
} else {
39-
this.stsTokenFreshTime = now;
40-
}
41-
}
4230
if (this.options.stsToken) {
4331
options['security-token'] = this.options.stsToken;
4432
}

test/browser/browser.test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ const timemachine = require('timemachine');
2222

2323
timemachine.reset();
2424

25+
function sleep(time) {
26+
return new Promise(resolve => {
27+
setTimeout(resolve, time);
28+
});
29+
}
30+
2531
const cleanBucket = async store => {
2632
let result = await store.list({
2733
'max-keys': 1000
@@ -1079,6 +1085,31 @@ describe('browser', () => {
10791085
// http://www.aliyun.com/darwin-v4.4.2/ali-sdk/oss/get-meta.js?OSSAccessKeyId=
10801086
assert.equal(url.indexOf('http://www.aliyun.com/'), 0);
10811087
});
1088+
1089+
it('signatureUrl will should use refreshSTSToken', async () => {
1090+
let flag = false;
1091+
1092+
store = oss({
1093+
region: ossConfig.region,
1094+
accessKeyId: ossConfig.accessKeyId,
1095+
accessKeySecret: ossConfig.accessKeySecret,
1096+
stsToken: ossConfig.stsToken,
1097+
refreshSTSToken: () => {
1098+
flag = true;
1099+
return {
1100+
accessKeyId: 'b',
1101+
accessKeySecret: 'b',
1102+
stsToken: 'b'
1103+
};
1104+
},
1105+
bucket: ossConfig.bucket,
1106+
refreshSTSTokenInterval: 1000
1107+
});
1108+
1109+
await sleep(2000);
1110+
await store.asyncSignatureUrl('test.txt');
1111+
assert(flag);
1112+
});
10821113
});
10831114

10841115
describe('multipart', () => {

test/node/object.test.js

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,49 +1048,6 @@ describe('test/object.test.js', () => {
10481048
assert.equal(typeof object.res.headers['x-oss-request-id'], 'string');
10491049
});
10501050

1051-
it('should signature use setSTSToken', async () => {
1052-
const stsClient = sts(stsConfig);
1053-
const policy = {
1054-
Statement: [
1055-
{
1056-
Action: ['oss:*'],
1057-
Effect: 'Allow',
1058-
Resource: ['acs:oss:*:*:*']
1059-
}
1060-
],
1061-
Version: '1'
1062-
};
1063-
const response = await stsClient.assumeRole(stsConfig.roleArn, policy);
1064-
1065-
const tempStore = oss({
1066-
bucket: stsConfig.bucket,
1067-
accessKeyId: response.credentials.AccessKeyId,
1068-
accessKeySecret: response.credentials.AccessKeySecret,
1069-
region: config.region,
1070-
stsToken: response.credentials.SecurityToken,
1071-
refreshSTSToken: async () => {
1072-
const r = await stsClient.assumeRole(stsConfig.roleArn, policy);
1073-
return {
1074-
accessKeyId: r.credentials.AccessKeyId,
1075-
accessKeySecret: r.credentials.AccessKeySecret,
1076-
stsToken: r.credentials.SecurityToken
1077-
};
1078-
},
1079-
refreshSTSTokenInterval: 2000
1080-
});
1081-
const content = 'setSTSToken test';
1082-
await tempStore.put(name, Buffer.from(content));
1083-
const beforeUrl = tempStore.signatureUrl(name);
1084-
const urlRes = await urllib.request(beforeUrl);
1085-
assert.equal(urlRes.data.toString(), content);
1086-
const beforeTime = tempStore.stsTokenFreshTime;
1087-
await utils.sleep(ms(5000));
1088-
const afterUrl = tempStore.signatureUrl(name);
1089-
const afeterRes = await urllib.request(afterUrl);
1090-
assert.equal(afeterRes.data.toString(), content);
1091-
assert.notEqual(beforeTime, tempStore.stsTokenFreshTime);
1092-
});
1093-
10941051
it('should signature url get object ok', async () => {
10951052
try {
10961053
const result = await store.get(name);

test/node/sts.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ describe('test/sts.test.js', () => {
181181
};
182182
store = new OSS(testRefreshSTSTokenConf);
183183
});
184+
184185
it('should refresh sts token when token is expired', async () => {
185186
try {
186187
store.options.refreshSTSToken = async () => {
@@ -198,5 +199,31 @@ describe('test/sts.test.js', () => {
198199
assert(false, error);
199200
}
200201
});
202+
203+
it('asyncSignatureUrl will should use refreshSTSToken', async () => {
204+
const { credentials } = await stsClient.assumeRole(stsConfig.roleArn);
205+
let flag = false;
206+
207+
store = new OSS({
208+
region: config.region,
209+
accessKeyId: credentials.AccessKeyId,
210+
accessKeySecret: credentials.AccessKeySecret,
211+
stsToken: credentials.SecurityToken,
212+
refreshSTSToken: () => {
213+
flag = true;
214+
return {
215+
accessKeyId: 'b',
216+
accessKeySecret: 'b',
217+
stsToken: 'b'
218+
};
219+
},
220+
bucket: stsConfig.bucket,
221+
refreshSTSTokenInterval: 1000
222+
});
223+
await utils.sleep(2000);
224+
await store.asyncSignatureUrl('test.txt');
225+
226+
assert(flag);
227+
});
201228
});
202229
});

0 commit comments

Comments
 (0)