@shopify/shopify-api 14.0.0 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/lib/clients/common.js +64 -8
- package/dist/cjs/lib/clients/common.js.map +1 -1
- package/dist/cjs/lib/utils/fetch-request.js +12 -1
- package/dist/cjs/lib/utils/fetch-request.js.map +1 -1
- package/dist/cjs/lib/version.js +1 -1
- package/dist/cjs/lib/version.js.map +1 -1
- package/dist/cjs/tsconfig.build.tsbuildinfo +1 -1
- package/dist/esm/lib/clients/common.mjs +64 -8
- package/dist/esm/lib/clients/common.mjs.map +1 -1
- package/dist/esm/lib/utils/fetch-request.mjs +12 -1
- package/dist/esm/lib/utils/fetch-request.mjs.map +1 -1
- package/dist/esm/lib/version.mjs +1 -1
- package/dist/esm/lib/version.mjs.map +1 -1
- package/dist/esm/tsconfig.build.tsbuildinfo +1 -1
- package/dist/ts/lib/clients/common.d.ts.map +1 -1
- package/dist/ts/lib/utils/fetch-request.d.ts.map +1 -1
- package/dist/ts/lib/version.d.ts +1 -1
- package/dist/ts/tsconfig.build.tsbuildinfo +1 -1
- package/lib/clients/common.ts +91 -7
- package/lib/utils/fetch-request.ts +13 -1
- package/lib/version.ts +1 -1
- package/package.json +1 -1
package/lib/clients/common.ts
CHANGED
|
@@ -25,6 +25,86 @@ export function getUserAgent(config: ConfigInterface): string {
|
|
|
25
25
|
return userAgentPrefix;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
const REDACTED_LOG_VALUE = '****';
|
|
29
|
+
|
|
30
|
+
// These headers carry reusable credentials and must not reach the logs.
|
|
31
|
+
const SENSITIVE_LOG_HEADERS = new Set([
|
|
32
|
+
'authorization',
|
|
33
|
+
'cookie',
|
|
34
|
+
'set-cookie',
|
|
35
|
+
'shopify-storefront-private-token',
|
|
36
|
+
'x-shopify-access-token',
|
|
37
|
+
'x-shopify-storefront-access-token',
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
function sanitizeHeaderValue(name: string, value: unknown): unknown {
|
|
41
|
+
return SENSITIVE_LOG_HEADERS.has(name.toLowerCase())
|
|
42
|
+
? REDACTED_LOG_VALUE
|
|
43
|
+
: value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Keep the original serialized shape of request headers. A Headers instance
|
|
47
|
+
// has no own enumerable properties, so it stays opaque here, the same as
|
|
48
|
+
// JSON.stringify shows it.
|
|
49
|
+
function sanitizeHeaders(headers: any): any {
|
|
50
|
+
if (!headers || typeof headers !== 'object') {
|
|
51
|
+
return headers;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (Array.isArray(headers)) {
|
|
55
|
+
return headers.map((header) =>
|
|
56
|
+
Array.isArray(header)
|
|
57
|
+
? [header[0], sanitizeHeaderValue(header[0], header[1])]
|
|
58
|
+
: header,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return Object.fromEntries(
|
|
63
|
+
Object.entries(headers).map(([name, value]) => [
|
|
64
|
+
name,
|
|
65
|
+
sanitizeHeaderValue(name, value),
|
|
66
|
+
]),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Response headers were always enumerated in the log, so keep that and
|
|
71
|
+
// redact the credential values.
|
|
72
|
+
function sanitizeEnumerableHeaders(headers: any): any {
|
|
73
|
+
if (typeof headers?.entries === 'function' && !Array.isArray(headers)) {
|
|
74
|
+
return Object.fromEntries(
|
|
75
|
+
[...headers.entries()].map(([name, value]: [string, string]) => [
|
|
76
|
+
name,
|
|
77
|
+
sanitizeHeaderValue(name, value),
|
|
78
|
+
]),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return sanitizeHeaders(headers);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function sanitizeRequestParams<T>(requestParams: T): T {
|
|
86
|
+
if (Array.isArray(requestParams)) {
|
|
87
|
+
return requestParams.map((param) =>
|
|
88
|
+
param && typeof param === 'object' && 'headers' in param
|
|
89
|
+
? {...param, headers: sanitizeHeaders(param.headers)}
|
|
90
|
+
: param,
|
|
91
|
+
) as T;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
requestParams &&
|
|
96
|
+
typeof requestParams === 'object' &&
|
|
97
|
+
'headers' in requestParams
|
|
98
|
+
) {
|
|
99
|
+
return {
|
|
100
|
+
...requestParams,
|
|
101
|
+
headers: sanitizeHeaders((requestParams as {headers: any}).headers),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return requestParams;
|
|
106
|
+
}
|
|
107
|
+
|
|
28
108
|
function serializeResponse(response: Response | any) {
|
|
29
109
|
if (!response) {
|
|
30
110
|
return {error: 'No response object provided'};
|
|
@@ -42,10 +122,8 @@ function serializeResponse(response: Response | any) {
|
|
|
42
122
|
url,
|
|
43
123
|
};
|
|
44
124
|
|
|
45
|
-
if (headers
|
|
46
|
-
serialized.headers =
|
|
47
|
-
} else if (headers) {
|
|
48
|
-
serialized.headers = headers;
|
|
125
|
+
if (headers) {
|
|
126
|
+
serialized.headers = sanitizeEnumerableHeaders(headers);
|
|
49
127
|
}
|
|
50
128
|
|
|
51
129
|
return serialized;
|
|
@@ -61,7 +139,9 @@ export function clientLoggerFactory(config: ConfigInterface) {
|
|
|
61
139
|
case 'HTTP-Response': {
|
|
62
140
|
const responseLog: HTTPResponseLog['content'] = logContent.content;
|
|
63
141
|
logger(config).debug('Received response for HTTP request', {
|
|
64
|
-
requestParams: JSON.stringify(
|
|
142
|
+
requestParams: JSON.stringify(
|
|
143
|
+
sanitizeRequestParams(responseLog.requestParams),
|
|
144
|
+
),
|
|
65
145
|
response: JSON.stringify(serializeResponse(responseLog.response)),
|
|
66
146
|
});
|
|
67
147
|
break;
|
|
@@ -69,7 +149,9 @@ export function clientLoggerFactory(config: ConfigInterface) {
|
|
|
69
149
|
case 'HTTP-Retry': {
|
|
70
150
|
const responseLog: HTTPRetryLog['content'] = logContent.content;
|
|
71
151
|
logger(config).debug('Retrying HTTP request', {
|
|
72
|
-
requestParams: JSON.stringify(
|
|
152
|
+
requestParams: JSON.stringify(
|
|
153
|
+
sanitizeRequestParams(responseLog.requestParams),
|
|
154
|
+
),
|
|
73
155
|
retryAttempt: responseLog.retryAttempt,
|
|
74
156
|
maxRetries: responseLog.maxRetries,
|
|
75
157
|
response: responseLog.lastResponse
|
|
@@ -84,7 +166,9 @@ export function clientLoggerFactory(config: ConfigInterface) {
|
|
|
84
166
|
logger(config).debug(
|
|
85
167
|
'Received response containing Deprecated GraphQL Notice',
|
|
86
168
|
{
|
|
87
|
-
requestParams: JSON.stringify(
|
|
169
|
+
requestParams: JSON.stringify(
|
|
170
|
+
sanitizeRequestParams(responseLog.requestParams),
|
|
171
|
+
),
|
|
88
172
|
deprecationNotice: responseLog.deprecationNotice,
|
|
89
173
|
},
|
|
90
174
|
);
|
|
@@ -3,6 +3,18 @@ import {LogSeverity} from '../types';
|
|
|
3
3
|
import {abstractFetch} from '../../runtime';
|
|
4
4
|
import {ConfigInterface} from '../base-types';
|
|
5
5
|
|
|
6
|
+
const OAUTH_TOKEN_ENDPOINT_PATH = '/admin/oauth/access_token';
|
|
7
|
+
|
|
8
|
+
// Token endpoint bodies carry OAuth secrets, so they must not reach the logs.
|
|
9
|
+
// When the URL does not parse, fail closed and keep the body out of the logs.
|
|
10
|
+
function canLogRequestBody(url: string): boolean {
|
|
11
|
+
try {
|
|
12
|
+
return new URL(url).pathname !== OAUTH_TOKEN_ENDPOINT_PATH;
|
|
13
|
+
} catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
6
18
|
export function fetchRequestFactory(config: ConfigInterface) {
|
|
7
19
|
return async function fetchRequest(
|
|
8
20
|
url: string,
|
|
@@ -16,7 +28,7 @@ export function fetchRequestFactory(config: ConfigInterface) {
|
|
|
16
28
|
log.debug('Making HTTP request', {
|
|
17
29
|
method: options?.method || 'GET',
|
|
18
30
|
url,
|
|
19
|
-
...(options?.body && {body: options
|
|
31
|
+
...(options?.body && canLogRequestBody(url) && {body: options.body}),
|
|
20
32
|
});
|
|
21
33
|
}
|
|
22
34
|
|
package/lib/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SHOPIFY_API_LIBRARY_VERSION = '14.0.
|
|
1
|
+
export const SHOPIFY_API_LIBRARY_VERSION = '14.0.1';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopify/shopify-api",
|
|
3
|
-
"version": "14.0.
|
|
3
|
+
"version": "14.0.1",
|
|
4
4
|
"description": "Shopify API Library for Node - accelerate development with support for authentication, graphql proxy, webhooks",
|
|
5
5
|
"types": "./dist/ts/lib/index.d.ts",
|
|
6
6
|
"module": "./dist/esm/lib/index.mjs",
|