Skip to content

Commit

Permalink
adds a new export from the package for aws-sdk v3 (#758)
Browse files Browse the repository at this point in the history
* adds a new export from the package for aws-sdk v3

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* adds tests, doc updates and better error messages

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: add docs & missing license field

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: test

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: add license

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: tests & credential loader code

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: tests error due to dependency being installed now

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: tests

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* update yarn

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* use yarn install

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: update yarn.lock

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* fix: remove peer dependency

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* revert yarn lock

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

* use npm

Signed-off-by: Tushar Sharma <ts17995@gmail.com>

---------

Signed-off-by: Tushar Sharma <ts17995@gmail.com>
  • Loading branch information
tusharf5 authored Apr 24, 2024
1 parent 2aa2fd0 commit e93977a
Show file tree
Hide file tree
Showing 13 changed files with 393 additions and 152 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/bundler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,20 @@ jobs:
npm install --prefix test/bundlers/parcel-test
npm install --prefix test/bundlers/rollup-test
npm install --prefix test/bundlers/webpack-test
npm install --prefix test/bundlers/esbuild-test
- name: Build
run: |
npm run build --prefix test/bundlers/parcel-test
npm run build --prefix test/bundlers/rollup-test
npm run build --prefix test/bundlers/webpack-test
npm run build:aws --prefix test/bundlers/esbuild-test
npm run build:awsv3 --prefix test/bundlers/esbuild-test
- name: Run bundle
run: |
npm start --prefix test/bundlers/parcel-test
npm start --prefix test/bundlers/rollup-test
npm start --prefix test/bundlers/webpack-test
npm run start:aws --prefix test/bundlers/esbuild-test
npm run start:awsv3 --prefix test/bundlers/esbuild-test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ test/benchmarks/macro/fixtures/*

test/bundlers/**/bundle.js
test/bundlers/parcel-test/.parcel-cache
test/bundlers/esbuild-test/bundle-*.js
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]
### Added
- Added `@opensearch-project/opensearch/aws-v3` import ([758](https://github.com/opensearch-project/opensearch-js/pull/758)).
### Dependencies
- Bumps `@types/node` from 20.12.5 to 20.12.7
- Bumps `semver` from 5.7.1 to 7.6.0
Expand Down
4 changes: 3 additions & 1 deletion USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ const client = new Client({
```javascript
const { defaultProvider } = require('@aws-sdk/credential-provider-node'); // V3 SDK.
const { Client } = require('@opensearch-project/opensearch');
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws');
const { AwsSigv4Signer } = require('@opensearch-project/opensearch/aws-v3'); // use aws-v3 import path if you are using aws-sdk v3
// Unlike the import path in the v2 example above that lazy loads both aws-sdk v3 credential providers & entire aws-sdk v2 if available
// This will only lazy load the aws-sdk v3 credential providers

const client = new Client({
...AwsSigv4Signer({
Expand Down
32 changes: 32 additions & 0 deletions lib/aws/AwsSigv4Signer-sdk-v3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/

'use strict';
const AwsSigv4SignerError = require('./errors');
const { giveAwsV4Signer, giveAwsCredentialProviderLoader } = require('./shared');

const getAwsSDKCredentialsProvider = async () => {
try {
const awsV3 = await import('@aws-sdk/credential-provider-node');
if (typeof awsV3.defaultProvider === 'function') {
return awsV3.defaultProvider();
}
} catch (err) {
throw new AwsSigv4SignerError(
"Missing '@aws-sdk/credential-provider-node' module. Install it as a dependency."
);
}
};

const AwsSigv4Signer = giveAwsV4Signer(
giveAwsCredentialProviderLoader(getAwsSDKCredentialsProvider)
);

module.exports = AwsSigv4Signer;
154 changes: 4 additions & 150 deletions lib/aws/AwsSigv4Signer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@
*/

'use strict';
const Connection = require('../Connection');
const Transport = require('../Transport');
const aws4 = require('aws4');
const AwsSigv4SignerError = require('./errors');
const crypto = require('crypto');
const { toMs } = Transport.internals;
const { giveAwsV4Signer, giveAwsCredentialProviderLoader } = require('./shared');

const getAwsSDKCredentialsProvider = async () => {
// First try V3
Expand Down Expand Up @@ -49,150 +45,8 @@ const getAwsSDKCredentialsProvider = async () => {
);
};

const awsDefaultCredentialsProvider = () =>
new Promise((resolve, reject) => {
getAwsSDKCredentialsProvider()
.then((provider) => {
provider().then(resolve).catch(reject);
})
.catch((err) => {
reject(err);
});
});
const AwsSigv4Signer = giveAwsV4Signer(
giveAwsCredentialProviderLoader(getAwsSDKCredentialsProvider)
);

function AwsSigv4Signer(opts = {}) {
const credentialsState = {
credentials: null,
};
if (!opts.region) {
throw new AwsSigv4SignerError('Region cannot be empty');
}
if (!opts.service) {
opts.service = 'es';
}
if (typeof opts.getCredentials !== 'function') {
opts.getCredentials = awsDefaultCredentialsProvider;
}

function buildSignedRequestObject(request = {}) {
request.service = opts.service;
request.region = opts.region;
request.headers = request.headers || {};
request.headers['host'] = request.hostname;

if (request['auth']) {
const awssigv4Cred = request['auth'];
credentialsState.credentials = {
accessKeyId: awssigv4Cred.credentials.accessKeyId,
secretAccessKey: awssigv4Cred.credentials.secretAccessKey,
sessionToken: awssigv4Cred.credentials.sessionToken,
};
request.region = awssigv4Cred.region;
request.service = awssigv4Cred.service;
delete request['auth'];
}
const signed = aws4.sign(request, credentialsState.credentials);
signed.headers['x-amz-content-sha256'] = crypto
.createHash('sha256')
.update(request.body || '', 'utf8')
.digest('hex');
return signed;
}

class AwsSigv4SignerConnection extends Connection {
buildRequestObject(params) {
const request = super.buildRequestObject(params);
return buildSignedRequestObject(request);
}
}

class AwsSigv4SignerTransport extends Transport {
request(params, options = {}, callback = undefined) {
// options is optional so if options is a function, it's the callback.
if (typeof options === 'function') {
callback = options;
options = {};
}

const currentCredentials = credentialsState.credentials;
/**
* For AWS SDK V3
* Make sure token will expire no earlier than `expiryBufferMs` milliseconds in the future.
*/
const expiryBufferMs = toMs(options.requestTimeout || this.requestTimeout);

let expired = false;
if (!currentCredentials) {
// Credentials haven't been acquired yet.
expired = true;
}
// AWS SDK V2, needsRefresh should be available.
else if (typeof currentCredentials.needsRefresh === 'function') {
expired = currentCredentials.needsRefresh();
}
// AWS SDK V2, alternative to needsRefresh.
else if (currentCredentials.expired === true) {
expired = true;
}
// AWS SDK V2, alternative to needsRefresh and expired.
else if (currentCredentials.expireTime && currentCredentials.expireTime < new Date()) {
expired = true;
}
// AWS SDK V3, Credentials.expiration is a Date object
else if (
currentCredentials.expiration &&
currentCredentials.expiration.getTime() - Date.now() < expiryBufferMs
) {
expired = true;
}

if (!expired) {
if (typeof callback === 'undefined') {
return super.request(params, options);
}
super.request(params, options, callback);
return;
}

// In AWS SDK V2 Credentials.refreshPromise should be available.
if (currentCredentials && typeof currentCredentials.refreshPromise === 'function') {
if (typeof callback === 'undefined') {
return currentCredentials.refreshPromise().then(() => {
return super.request(params, options);
});
} else {
currentCredentials
.refreshPromise()
.then(() => {
super.request(params, options, callback);
})
.catch(callback);
return;
}
}

// For AWS SDK V3 or when the client has not acquired credentials yet.
if (typeof callback === 'undefined') {
return opts.getCredentials().then((credentials) => {
credentialsState.credentials = credentials;
return super.request(params, options);
});
} else {
opts
.getCredentials()
.then((credentials) => {
credentialsState.credentials = credentials;
super.request(params, options, callback);
})
.catch(callback);
}
}
}

return {
Transport: AwsSigv4SignerTransport,
Connection: AwsSigv4SignerConnection,
buildSignedRequestObject,
};
}
module.exports = AwsSigv4Signer;
19 changes: 19 additions & 0 deletions lib/aws/index-v3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*
*/

'use strict';

const AwsSigv4Signer = require('./AwsSigv4Signer-sdk-v3');
const AwsSigv4SignerError = require('./errors');

module.exports = {
AwsSigv4Signer,
AwsSigv4SignerError,
};
Loading

0 comments on commit e93977a

Please sign in to comment.