Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@adobe/cloud-service-client
Advanced tools
This client can be used to submit HTTP requests in javascript. You may ask, "why use this client instead of one of the more popular libraries?"
First off, it's not a rewrite of HTTP functionality for Node.JS; it's still intended for use with popular modules (like fetch
or axios
) for the actual HTTP handling. Think of the client more like added functionality built on top of the basic HTTP capabilities that these modules provide; these features are commonly required when communicating with a complex cloud service.
Here is some of this functionality:
axios
or fetch
. Currently using fetch
and need to take advantage of the client's retry functionality? Simply replace your fetch
calls with the client; everything else (such as response format, options, etc.) will fit into place seamlessly.The module can be installed from npm:
npm install @adobe/cloud-service-client
Following are some example of how to use the client.
const originalAxios = require('axios');
const { axiosClient } = require('@adobe/cloud-service-client');
// add client functionality to axios
const axios = axiosClient(originalAxios);
// submit a request that will behave like axios:
const response = await axios('http://myrequesturl.com');
// the response will follow axios' response schema:
const {
data,
status,
statusText,
headers
} = response;
// axios' other methods work as well:
const response = await axios.get('http://myrequesturl.com);
// pass in any of axios' options:
const response = await axios({
url: 'http://myrequesturl.com',
method: 'get',
responseType: 'stream'
});
const nodeFetch = require('node-fetch');
const { fetchClient } = require('@adobe/cloud-service-client');
// add client functionality to node-fetch
const fetch = fetchClient(nodeFetch);
// submit the request as fetch would
const response = await fetch('http://myrequesturl.com');
// the response will follow fetch's schema:
const {
status,
statusText,
headers
} = response;
const header1 = headers.get('my-header);
const data = await response.json();
if (response.ok) {
// process successful response
}
// pass in any of fetch's options:
const response = await fetch('http://myrequesturl.com', {
method: 'get',
mode: 'cors',
redirect: 'follow'
});
In addition to providing exports identical to whichever HTTP library is being used, the client provides the following functionality:
clearCookies
: When invoked, clears any cookies that the client may currently be storing. The method returns a Promise
that
will resolve when the client's cookies have been cleared.
const { clearCookies } = require('@adobe/cloud-service-client');
setGlobalOptions
: Takes a single argument that should be any client-specific request options to apply to all requests that the client sends. Note that this only applies to the client's request options as described in Request Options; options should be provided to the function as they would to the cloudClient
property. The underlying
HTTP library of choice (i.e. axios
or fetch
) should be used to apply other global request-level options.
const { setGlobalOptions } = require('@adobe/cloud-service-client');
setGlobalOptions({ eventuallyConsistentCreate: true });
Exports like axiosClient()
and fetchClient()
accept an optional second argument, which should be a simple object containing any of the following configurations:
handleCookies
: If true
, the client will use its cookie processing capabilities to provide the cookie handling functionality described in the "Cookies" section. Default: false
.log
: See Logging section for more details.For example:
const axios = axiosClient(originalAxios, {
handleCookies: true,
});
In addition to any options supported by axios
or fetch
, the client has some request options of its own. These options should all be provided in an cloudClient
property on the request's configuration. For example:
fetch(url, {
method: 'POST',
mode: 'cors',
cloudClient: {
timeout: 10000,
eventuallyConsistentCreate: true
}
});
timeout
: The amount of time, in milliseconds, that the client will wait for a request before aborting. By default, an aborted request qualifies for a retry, so timed out requests will fit in with the client's retry functionality.retry
: Various information about how the client will retry requests under certain circumstances.
strategies
: The retry "strategies" that the client will send a response through before determining whether the corresponding request needs to be retried. See the "retry" section for more information and examples. Note that these strategies will be in addition to the client's default strategies, which will retry on unexpected network-related errors or 5xx level status codes. Each item in the array should be a strategy object consisting of the following properties:
shouldRetry
: Should return a Promise
that resolves to true if the information provided by the client warrants a retry. The function will be passed a single argument: an object consisting of the following properties:
getDelayMultiple
: Should return a Promise
that resolves to the multiple to use when calculating the amount of time to delay before retrying the request. The function will be called with a single argument: an object matching the object described in the shouldRetry
function. If not specified the value will default to the multiple provided in the client's retry options.getMaxRetries
: Should return a Promise
that resolves to the maximum number of times that a given request should be made. The function will be called with a single argument: an object matching the object described in the shouldRetry
function. If not specified, the value will default to the number provided in the client's retry options. Note that -1
indicates the client should continue to retry indefinitely; use this option with extreme care.count
: The maximum number of times the client will retry a given request. Note that this is a default value and will not necessarily be respected by all retry strategies. Default: 3.delay
: The amount of time, in milliseconds, the client will wait before retrying a request when needed. Default: 1000.delayMultiple
: Each time the client delays a retry, it will multiply the delay
amount by this value. Assume delay
is 1000, retry
is 4, and delayMultiple
is 2. The first time the client retries a request it will wait 1000ms, the second time it will wait 2000ms, the third time it will wait 4000ms, etc. Note that
this is a default value and will not necessarily be respected by all retry strategies. Default: 2.eventuallyConsistentCreate
: When true
, the client will use a built-in retry strategy for handling creation in an eventually consistent system. See the "Retry" section for more details. Default: false
.eventuallyConsistentUpdate
: When true
, the client will use a built-in retry strategy for handling updates in an eventually consistent system. See the "Retry" section for more details. Default: false
.eventuallyConsistentDelete
: When true
, the client will use a built-in retry strategy for handling deletions in an eventually consistent system. See the "Retry" section for more details. Default: false
.The client will extend the HTTP response provided by the underlying HTTP library with an cloudClient
property. Additional information available on this property is as follows:
status
: Status code of the response. Note that this value may be missing if the request did not generate a response (such as timeout errors or general network-related errors).statusText
: Status text of the response. Note that this value may be missing if the request did not generate a response (such as timeout errors or general network-related errors).requestTime
: The amount of time, in milliseconds, that the underlying HTTP library took submitting the request and receiving a response. Note that this will apply to last request that was sent. The value may be missing if the request's time
could not be determined.headers
: Simple object whose keys are header names and values are header values. These are the HTTP headers that were provided in the response.options
: The options that were provided to the client when initiating the request. The object will have an cloudClient
property (regardless of whether one was initially provided) with the following additional properties added to it:
retryResponses
: If the request was retried, a list of each response, in order, that resulted in a retry. Each item in the list will include all the items included in this section for the response that was retried.
retries
: The number of retries that were made for before providing a response.retryWait
: The amount of time, in milliseconds, that the client spent waiting between retries before providing a response.startTime
: Unix timestamp of the time when the request was initiated.endTime
: Unix timestamp of the time when the client recieved a response.error
: Simple object containing information about the error that the underlying HTTP library may have provided. This property will only be present if there was an error, and its contents may vary depending on the error that was thrown. If the
error is a known javascript error type, it contain the following properties:
name
: The name of the error.message
: Message that was associated with the error.The client has built-in support for retrying a given request under certain circumstances. These circumstances are determined by "request retry strategies." In concept, the client has a list of strategies; each strategy is responsible for examining the response to a request and indicating whether the request qualifies for a retry. Whenever the client makes a request, it will pass the response through its list of strategies. The first strategy that indicates the request should be retried will force the client to retry the request. The client will use this algorithm regardless of whether the response can be considered a "success" or a "failure."
By default the client will retry a request up to a maximum number of times, exponentially delaying the amount of time between each retry. However, this behavior can be overridden by individual strategies.
The following client will retry a request up to 5 times if the response code is 404
:
axios({
url: 'http://myurltorequest',
cloudClient: {
retry: {
count: 4,
strategies: [{
shouldRetry: async ({ response }) => response.status === 404
}]
}
}
});
This client will poll a URL for as long as the response code is 202
, waiting the same amount of time between each request:
axios({
url: 'http://myurltorequest',
cloudClient: {
retry: {
strategies: [{
shouldRetry: async ({ response }) => response.status === 202,
getDelayMultiple: async () => 1,
getMaxRetries: async () => -1,
}]
}
}
});
(Be very careful with a setup like this, because the client will poll indefinitely)
By default the client will always retry requests that fail because of network-related issues, or that have a 5xx level response code.
In addition, the client provides the following optional strategies. Note that "Eventually Consistent" refers to the concept where there may be a delay between when a remote system is modified, and when the said modification is reflected in the system.
etag
header doesn't match the if-match
header provided in the request.See the retry options for how to utilize these strategies.
If configured to do so, the client has some basic cookie handling in place. For example, if a response handled by the client has a Set-Cookie
header, the client will cache those cookies and include them in any subsequent requests that it sends. Note that the cookies are scoped to the lifetime of the client instance - they're not
persisted and will be lost when the client goes out of scope.
The client will favor cookies passed in a request's options over any cookies it has stored. For example, assume that the client is storing cookie mycookie
with a value of set-cookie-value
because it received it in a Set-Cookie
header. Also assume that a consumer of the
client passes the same cookie in the Cookie
header with a value of options-cookie-value
when initiating a request. In this case the client will use options-cookie-value
as the value of mycookie
, because it was passed into the request options.
Cookies specified with Set-Cookie
will follow the HTTP specification for the header, and will honor attributes such as Path
, Domain
, Max-Age
, Expires
, Secure
, etc. The main deviance is that the life of the cookie will always be, at maximum, the client's scope.
This functionality will only be enabled when the handleCookies
options is true
.
The client will log messages at different levels throughout the request process. By default none of these messages will appear anywhere; change that behavior by using one of the following methods.
Set an environment variable named NODE_HTTP_CLIENT_LOG_LEVEL
to the level of logging that is desired. Valid values are DEBUG
, INFO
, WARN
, or ERROR
.
When utilizing this logging mechanism, all messages are written to console.log()
. Use the custom logger method to change that behavior.
Use the log
option to provide any logger of your choosing:
const axiosOriginal = require('axios');
const { axiosClient } = require('@adobe/cloud-service-client');
const axios = axiosClient(axiosOriginal, {
log: {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
}
});
const response = await axios('http://myrequesturl.com',);
As illustrated in the example, the logger provided must have the following methods:
debug()
info()
warn()
error()
Each method is used by the client to log a message at its corresponding log level. The method will receive multiple arguments, similar in nature to how console.log()
might be used. Here are some potential examples:
log.debug('simple message');
log.info('formatted message with value %s', formatValue);
log.error('non-formatted message with value', someValue);
See the library's end-to-end contract tests for various examples of how to use the library.
This module uses semantic-release when publishing new versions. The process is initiated upon merging commits to the master
branch. To create a release, ensure
that the commit message of the PR begins with one of the following values:
BREAKING-RELEASE:
major
version number (i.e. 1.2.3 would become 2.0.0)FEATURE-RELEASE:
minor
version number (i.e. 1.2.3 would become 1.3.0)BUGFIX-RELEASE:
patch
version number (i.e. 1.2.3 would become 1.2.4)PRs whose messages do not meet this format will not generate a new release.
Release notes are generated based on semantic-release's eslint preset. Follow the guidelines in the preset's documentation to include commit messages in a release's notes.
As a quick example, the following illustrates a commit that will be included as a bug fix in the release notes:
Fix: Fixed in issue with the client (fixes #1234)
This can be a longer description of what the issue fixes.
Contributions are welcomed! Read the Contributing Guide for more information.
This project is licensed under the Apache V2 License. See LICENSE for more information.
FAQs
Client for working with an HTTP-based cloud service
We found that @adobe/cloud-service-client demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 24 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.