Skip to content

Commit 69a1e11

Browse files
authored
Merge pull request github#3609 from erik-krogh/CredFN
Approved by asgerf, esbena
2 parents ad2d1d5 + e477702 commit 69a1e11

File tree

5 files changed

+212
-10
lines changed

5 files changed

+212
-10
lines changed

change-notes/1.25/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer results | This query now recognizes additional safe patterns of doing URL redirects. |
4444
| Code injection (`js/code-injection`) | More results | More potential vulnerabilities involving NoSQL code operators are now recognized. |
4545
| Expression has no effect (`js/useless-expression`) | Fewer results | This query no longer flags an expression when that expression is the only content of the containing file. |
46+
| Hard-coded credentials (`js/hardcoded-credentials`) | More results | This query now recognizes hard-coded credentials sent via HTTP authorization headers. |
4647
| Incomplete URL scheme check (`js/incomplete-url-scheme-check`) | More results | This query now recognizes additional url scheme checks. |
4748
| Misspelled variable name (`js/misspelled-variable-name`) | Message changed | The message for this query now correctly identifies the misspelled variable in additional cases. |
4849
| Prototype pollution in utility function (`js/prototype-pollution-utility`) | More results | This query now recognizes additional utility functions as vulnerable to prototype polution. |

javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -260,25 +260,38 @@ module ClientRequest {
260260
}
261261
}
262262

263+
/** An expression that is used as a credential in a request. */
264+
private class AuthorizationHeader extends CredentialsExpr {
265+
AuthorizationHeader() {
266+
exists(DataFlow::PropWrite write | write.getPropertyName().regexpMatch("(?i)authorization") |
267+
this = write.getRhs().asExpr()
268+
)
269+
or
270+
exists(DataFlow::MethodCallNode call | call.getMethodName() = ["append", "set"] |
271+
call.getNumArgument() = 2 and
272+
call.getArgument(0).getStringValue().regexpMatch("(?i)authorization") and
273+
this = call.getArgument(1).asExpr()
274+
)
275+
}
276+
277+
override string getCredentialsKind() { result = "authorization header" }
278+
}
279+
263280
/**
264281
* A model of a URL request made using an implementation of the `fetch` API.
265282
*/
266283
class FetchUrlRequest extends ClientRequest::Range {
267284
DataFlow::Node url;
268285

269286
FetchUrlRequest() {
270-
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
271-
(
272-
moduleName = "node-fetch" or
273-
moduleName = "cross-fetch" or
274-
moduleName = "isomorphic-fetch"
275-
) and
276-
callee = DataFlow::moduleImport(moduleName) and
287+
exists(DataFlow::SourceNode fetch |
288+
fetch = DataFlow::moduleImport(["node-fetch", "cross-fetch", "isomorphic-fetch"])
289+
or
290+
fetch = DataFlow::globalVarRef("fetch") // https://fetch.spec.whatwg.org/#fetch-api
291+
|
292+
this = fetch.getACall() and
277293
url = getArgument(0)
278294
)
279-
or
280-
this = DataFlow::globalVarRef("fetch").getACall() and
281-
url = getArgument(0)
282295
}
283296

284297
override DataFlow::Node getUrl() { result = url }

javascript/ql/src/semmle/javascript/security/dataflow/HardcodedCredentials.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,18 @@ module HardcodedCredentials {
2020
override predicate isSource(DataFlow::Node source) { source instanceof Source }
2121

2222
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
23+
24+
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) {
25+
exists(Base64::Encode encode | src = encode.getInput() and trg = encode.getOutput())
26+
or
27+
trg.(StringOps::ConcatenationRoot).getALeaf() = src and
28+
not exists(src.(StringOps::ConcatenationLeaf).getStringValue()) // to avoid e.g. the ":" in `user + ":" + pass` being flagged as a constant credential.
29+
or
30+
exists(DataFlow::MethodCallNode bufferFrom |
31+
bufferFrom = DataFlow::globalVarRef("Buffer").getAMethodCall("from") and
32+
trg = bufferFrom and
33+
src = bufferFrom.getArgument(0)
34+
)
35+
}
2336
}
2437
}

javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.expected

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,52 @@ nodes
162162
| HardcodedCredentials.js:164:35:164:45 | 'change_me' |
163163
| HardcodedCredentials.js:164:35:164:45 | 'change_me' |
164164
| HardcodedCredentials.js:164:35:164:45 | 'change_me' |
165+
| HardcodedCredentials.js:171:11:171:25 | USER |
166+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' |
167+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' |
168+
| HardcodedCredentials.js:172:11:172:25 | PASS |
169+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' |
170+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' |
171+
| HardcodedCredentials.js:173:11:173:49 | AUTH |
172+
| HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) |
173+
| HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` |
174+
| HardcodedCredentials.js:173:35:173:38 | USER |
175+
| HardcodedCredentials.js:173:43:173:46 | PASS |
176+
| HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` |
177+
| HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` |
178+
| HardcodedCredentials.js:178:39:178:42 | AUTH |
179+
| HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` |
180+
| HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` |
181+
| HardcodedCredentials.js:188:39:188:42 | AUTH |
182+
| HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` |
183+
| HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` |
184+
| HardcodedCredentials.js:195:46:195:49 | AUTH |
185+
| HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
186+
| HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
187+
| HardcodedCredentials.js:204:44:204:47 | AUTH |
188+
| HardcodedCredentials.js:214:11:214:25 | USER |
189+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' |
190+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' |
191+
| HardcodedCredentials.js:215:11:215:25 | PASS |
192+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' |
193+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' |
194+
| HardcodedCredentials.js:216:11:216:49 | AUTH |
195+
| HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) |
196+
| HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` |
197+
| HardcodedCredentials.js:216:35:216:38 | USER |
198+
| HardcodedCredentials.js:216:43:216:46 | PASS |
199+
| HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
200+
| HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
201+
| HardcodedCredentials.js:221:46:221:49 | AUTH |
202+
| HardcodedCredentials.js:231:11:231:29 | username |
203+
| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' |
204+
| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' |
205+
| HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') |
206+
| HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') |
207+
| HardcodedCredentials.js:237:35:237:72 | Buffer. ... ssword) |
208+
| HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') |
209+
| HardcodedCredentials.js:237:47:237:54 | username |
210+
| HardcodedCredentials.js:237:47:237:71 | usernam ... assword |
165211
edges
166212
| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' |
167213
| HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' |
@@ -220,6 +266,49 @@ edges
220266
| HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" |
221267
| HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' |
222268
| HardcodedCredentials.js:164:35:164:45 | 'change_me' | HardcodedCredentials.js:164:35:164:45 | 'change_me' |
269+
| HardcodedCredentials.js:171:11:171:25 | USER | HardcodedCredentials.js:173:35:173:38 | USER |
270+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:11:171:25 | USER |
271+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:11:171:25 | USER |
272+
| HardcodedCredentials.js:172:11:172:25 | PASS | HardcodedCredentials.js:173:43:173:46 | PASS |
273+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:11:172:25 | PASS |
274+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:11:172:25 | PASS |
275+
| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:178:39:178:42 | AUTH |
276+
| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:188:39:188:42 | AUTH |
277+
| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:195:46:195:49 | AUTH |
278+
| HardcodedCredentials.js:173:11:173:49 | AUTH | HardcodedCredentials.js:204:44:204:47 | AUTH |
279+
| HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) | HardcodedCredentials.js:173:11:173:49 | AUTH |
280+
| HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` | HardcodedCredentials.js:173:18:173:49 | base64. ... PASS}`) |
281+
| HardcodedCredentials.js:173:35:173:38 | USER | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` |
282+
| HardcodedCredentials.js:173:43:173:46 | PASS | HardcodedCredentials.js:173:32:173:48 | `${USER}:${PASS}` |
283+
| HardcodedCredentials.js:178:39:178:42 | AUTH | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` |
284+
| HardcodedCredentials.js:178:39:178:42 | AUTH | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` |
285+
| HardcodedCredentials.js:188:39:188:42 | AUTH | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` |
286+
| HardcodedCredentials.js:188:39:188:42 | AUTH | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` |
287+
| HardcodedCredentials.js:195:46:195:49 | AUTH | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` |
288+
| HardcodedCredentials.js:195:46:195:49 | AUTH | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` |
289+
| HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
290+
| HardcodedCredentials.js:204:44:204:47 | AUTH | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` |
291+
| HardcodedCredentials.js:214:11:214:25 | USER | HardcodedCredentials.js:216:35:216:38 | USER |
292+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:11:214:25 | USER |
293+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:11:214:25 | USER |
294+
| HardcodedCredentials.js:215:11:215:25 | PASS | HardcodedCredentials.js:216:43:216:46 | PASS |
295+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:11:215:25 | PASS |
296+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:11:215:25 | PASS |
297+
| HardcodedCredentials.js:216:11:216:49 | AUTH | HardcodedCredentials.js:221:46:221:49 | AUTH |
298+
| HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) | HardcodedCredentials.js:216:11:216:49 | AUTH |
299+
| HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` | HardcodedCredentials.js:216:18:216:49 | base64. ... PASS}`) |
300+
| HardcodedCredentials.js:216:35:216:38 | USER | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` |
301+
| HardcodedCredentials.js:216:43:216:46 | PASS | HardcodedCredentials.js:216:32:216:48 | `${USER}:${PASS}` |
302+
| HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
303+
| HardcodedCredentials.js:221:46:221:49 | AUTH | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` |
304+
| HardcodedCredentials.js:231:11:231:29 | username | HardcodedCredentials.js:237:47:237:54 | username |
305+
| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:11:231:29 | username |
306+
| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:11:231:29 | username |
307+
| HardcodedCredentials.js:237:35:237:72 | Buffer. ... ssword) | HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') |
308+
| HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') |
309+
| HardcodedCredentials.js:237:35:237:91 | Buffer. ... ase64') | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') |
310+
| HardcodedCredentials.js:237:47:237:54 | username | HardcodedCredentials.js:237:47:237:71 | usernam ... assword |
311+
| HardcodedCredentials.js:237:47:237:71 | usernam ... assword | HardcodedCredentials.js:237:35:237:72 | Buffer. ... ssword) |
223312
#select
224313
| HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | The hard-coded value "dbuser" is used as $@. | HardcodedCredentials.js:5:15:5:22 | 'dbuser' | user name |
225314
| HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:8:19:8:28 | 'abcdefgh' | password |
@@ -274,3 +363,14 @@ edges
274363
| HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | The hard-coded value "abcdefgh" is used as $@. | HardcodedCredentials.js:135:41:135:50 | "abcdefgh" | key |
275364
| HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | HardcodedCredentials.js:160:38:160:48 | "change_me" | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:160:38:160:48 | "change_me" | key |
276365
| HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | HardcodedCredentials.js:161:41:161:51 | 'change_me' | The hard-coded value "change_me" is used as $@. | HardcodedCredentials.js:161:41:161:51 | 'change_me' | key |
366+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization header |
367+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization header |
368+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization header |
369+
| HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:171:18:171:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization header |
370+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:178:30:178:44 | `Basic ${AUTH}` | authorization header |
371+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:188:30:188:44 | `Basic ${AUTH}` | authorization header |
372+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:195:37:195:51 | `Basic ${AUTH}` | authorization header |
373+
| HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:172:18:172:25 | 'sdsdag' | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:204:35:204:49 | `Basic ${AUTH}` | authorization header |
374+
| HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:214:18:214:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization header |
375+
| HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:215:18:215:25 | 'sdsdag' | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:221:37:221:51 | `Basic ${AUTH}` | authorization header |
376+
| HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:231:22:231:29 | 'sdsdag' | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | The hard-coded value "sdsdag" is used as $@. | HardcodedCredentials.js:237:24:237:91 | 'Basic ... ase64') | authorization header |

javascript/ql/test/query-tests/Security/CWE-798/HardcodedCredentials.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,78 @@
163163
var basicAuth = require('express-basic-auth');
164164
basicAuth({users: { [adminName]: 'change_me' }}); // OK
165165
})();
166+
167+
(async function () {
168+
const base64 = require('base-64');
169+
const fetch = require("node-fetch");
170+
171+
const USER = 'sdsdag';
172+
const PASS = 'sdsdag';
173+
const AUTH = base64.encode(`${USER}:${PASS}`);
174+
175+
const rsp = await fetch(ENDPOINT, {
176+
method: 'get',
177+
headers: new fetch.Headers({
178+
"Authorization": `Basic ${AUTH}`,
179+
"Content-Type": 'application/json'
180+
})
181+
});
182+
183+
fetch(ENDPOINT, {
184+
method: 'post',
185+
body: JSON.stringify(body),
186+
headers: {
187+
"Content-Type": 'application/json',
188+
"Authorization": `Basic ${AUTH}`
189+
},
190+
})
191+
192+
var headers = new fetch.Headers({
193+
"Content-Type": 'application/json'
194+
});
195+
headers.append("Authorization", `Basic ${AUTH}`)
196+
fetch(ENDPOINT, {
197+
method: 'get',
198+
headers: headers
199+
});
200+
201+
var headers2 = new fetch.Headers({
202+
"Content-Type": 'application/json'
203+
});
204+
headers2.set("Authorization", `Basic ${AUTH}`)
205+
fetch(ENDPOINT, {
206+
method: 'get',
207+
headers: headers2
208+
});
209+
});
210+
211+
(function () {
212+
const base64 = require('base-64');
213+
214+
const USER = 'sdsdag';
215+
const PASS = 'sdsdag';
216+
const AUTH = base64.encode(`${USER}:${PASS}`);
217+
218+
// browser API
219+
var headers = new Headers();
220+
headers.append("Content-Type", 'application/json');
221+
headers.append("Authorization", `Basic ${AUTH}`);
222+
fetch(ENDPOINT, {
223+
method: 'get',
224+
headers: headers
225+
});
226+
});
227+
228+
(async function () {
229+
import fetch from 'node-fetch';
230+
231+
const username = 'sdsdag';
232+
const password = config.get('some_actually_secrect_password');
233+
const response = await fetch(ENDPOINT, {
234+
method: 'get',
235+
headers: {
236+
'Content-Type': 'application/json',
237+
Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'),
238+
},
239+
});
240+
})

0 commit comments

Comments
 (0)