@testsmith/api-spector 0.2.2 → 0.2.3
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/bin/cli.js +11 -3
- package/out/main/chunks/auth-builder-B7-LgcGr.js +373 -0
- package/out/main/chunks/{request-collection-Dx0ZqB54.js → request-collection-DMVlm0PA.js} +23 -349
- package/out/main/chunks/snapshots-C7YbGHM7.js +588 -0
- package/out/main/contract.js +210 -0
- package/out/main/index.js +78 -507
- package/out/main/runner.js +17 -16
- package/out/preload/index.js +4 -0
- package/out/renderer/assets/{index-DVaubmCJ.css → index-CxdQOFBM.css} +1 -1
- package/out/renderer/assets/{index-C_vjoxxA.js → index-DdHHEKaz.js} +997 -843
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
|
@@ -23,13 +23,14 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
));
|
|
24
24
|
const undici = require("undici");
|
|
25
25
|
const promises = require("fs/promises");
|
|
26
|
+
const authBuilder = require("./auth-builder-B7-LgcGr.js");
|
|
27
|
+
const vm = require("vm");
|
|
26
28
|
const crypto = require("crypto");
|
|
27
|
-
const path = require("path");
|
|
28
29
|
const dayjs = require("dayjs");
|
|
29
|
-
const vm = require("vm");
|
|
30
30
|
const tv4 = require("tv4");
|
|
31
31
|
const jsonpathPlus = require("jsonpath-plus");
|
|
32
32
|
const xmldom = require("@xmldom/xmldom");
|
|
33
|
+
const path = require("path");
|
|
33
34
|
const Ajv = require("ajv");
|
|
34
35
|
function _interopNamespaceDefault(e) {
|
|
35
36
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
@@ -47,8 +48,8 @@ function _interopNamespaceDefault(e) {
|
|
|
47
48
|
n.default = e;
|
|
48
49
|
return Object.freeze(n);
|
|
49
50
|
}
|
|
50
|
-
const crypto__namespace = /* @__PURE__ */ _interopNamespaceDefault(crypto);
|
|
51
51
|
const vm__namespace = /* @__PURE__ */ _interopNamespaceDefault(vm);
|
|
52
|
+
const crypto__namespace = /* @__PURE__ */ _interopNamespaceDefault(crypto);
|
|
52
53
|
let globals = {};
|
|
53
54
|
let currentDir = null;
|
|
54
55
|
function globalsPath(dir) {
|
|
@@ -77,171 +78,6 @@ function setGlobals(next) {
|
|
|
77
78
|
function patchGlobals(patch) {
|
|
78
79
|
globals = { ...globals, ...patch };
|
|
79
80
|
}
|
|
80
|
-
const MASTER_KEY_ENV = "API_SPECTOR_MASTER_KEY";
|
|
81
|
-
let secretStore = {};
|
|
82
|
-
let secretStorePath = null;
|
|
83
|
-
async function initSecretStore(userDataPath) {
|
|
84
|
-
secretStorePath = path.join(userDataPath, "secrets.json");
|
|
85
|
-
try {
|
|
86
|
-
const raw = await promises.readFile(secretStorePath, "utf8");
|
|
87
|
-
secretStore = JSON.parse(raw);
|
|
88
|
-
} catch {
|
|
89
|
-
secretStore = {};
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async function persistSecretStore() {
|
|
93
|
-
if (!secretStorePath) return;
|
|
94
|
-
await promises.writeFile(secretStorePath, JSON.stringify(secretStore, null, 2), "utf8");
|
|
95
|
-
}
|
|
96
|
-
function getSafeStorage() {
|
|
97
|
-
try {
|
|
98
|
-
const { safeStorage } = require("electron");
|
|
99
|
-
if (typeof safeStorage?.isEncryptionAvailable === "function") return safeStorage;
|
|
100
|
-
return null;
|
|
101
|
-
} catch {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
function registerSecretHandlers(ipc) {
|
|
106
|
-
ipc.handle("secret:checkMasterKey", () => {
|
|
107
|
-
return { set: Boolean(process.env[MASTER_KEY_ENV]) };
|
|
108
|
-
});
|
|
109
|
-
ipc.handle("secret:setMasterKey", (_e, value) => {
|
|
110
|
-
process.env[MASTER_KEY_ENV] = value;
|
|
111
|
-
});
|
|
112
|
-
ipc.handle("secret:set", async (_e, ref, value) => {
|
|
113
|
-
const ss = getSafeStorage();
|
|
114
|
-
if (!ss || !ss.isEncryptionAvailable()) {
|
|
115
|
-
throw new Error("OS encryption is not available — set the secret via environment variable instead");
|
|
116
|
-
}
|
|
117
|
-
secretStore[ref] = ss.encryptString(value).toString("base64");
|
|
118
|
-
await persistSecretStore();
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
function decryptSecret(encrypted, salt, iv, password) {
|
|
122
|
-
const saltBuf = Buffer.from(salt, "base64");
|
|
123
|
-
const ivBuf = Buffer.from(iv, "base64");
|
|
124
|
-
const encBuf = Buffer.from(encrypted, "base64");
|
|
125
|
-
const key = crypto.pbkdf2Sync(password, saltBuf, 1e5, 32, "sha256");
|
|
126
|
-
const authTag = encBuf.subarray(encBuf.length - 16);
|
|
127
|
-
const ciphertext = encBuf.subarray(0, encBuf.length - 16);
|
|
128
|
-
const decipher = crypto.createDecipheriv("aes-256-gcm", key, ivBuf);
|
|
129
|
-
decipher.setAuthTag(authTag);
|
|
130
|
-
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
131
|
-
}
|
|
132
|
-
async function getSecret(ref) {
|
|
133
|
-
const stored = secretStore[ref];
|
|
134
|
-
if (stored) {
|
|
135
|
-
const ss = getSafeStorage();
|
|
136
|
-
if (ss && ss.isEncryptionAvailable()) {
|
|
137
|
-
try {
|
|
138
|
-
return ss.decryptString(Buffer.from(stored, "base64"));
|
|
139
|
-
} catch {
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return process.env[ref] ?? null;
|
|
144
|
-
}
|
|
145
|
-
let _fakerCache$1 = null;
|
|
146
|
-
async function getFaker$1() {
|
|
147
|
-
if (!_fakerCache$1) _fakerCache$1 = await import("@faker-js/faker");
|
|
148
|
-
return _fakerCache$1.faker;
|
|
149
|
-
}
|
|
150
|
-
let _exprContext = null;
|
|
151
|
-
async function buildDynamicVars() {
|
|
152
|
-
const faker = await getFaker$1();
|
|
153
|
-
const now = dayjs();
|
|
154
|
-
_exprContext = { faker, dayjs };
|
|
155
|
-
return {
|
|
156
|
-
$uuid: faker.string.uuid(),
|
|
157
|
-
$timestamp: String(Date.now()),
|
|
158
|
-
$isoTimestamp: now.toISOString(),
|
|
159
|
-
$randomInt: String(faker.number.int({ min: 0, max: 1e3 })),
|
|
160
|
-
$randomFloat: String(faker.number.float({ min: 0, max: 1e3, fractionDigits: 2 })),
|
|
161
|
-
$randomBoolean: String(faker.datatype.boolean()),
|
|
162
|
-
$randomEmail: faker.internet.email(),
|
|
163
|
-
$randomUsername: faker.internet.username(),
|
|
164
|
-
$randomPassword: faker.internet.password(),
|
|
165
|
-
$randomFullName: faker.person.fullName(),
|
|
166
|
-
$randomFirstName: faker.person.firstName(),
|
|
167
|
-
$randomLastName: faker.person.lastName(),
|
|
168
|
-
$randomWord: faker.lorem.word(),
|
|
169
|
-
$randomPhrase: faker.lorem.sentence(),
|
|
170
|
-
$randomUrl: faker.internet.url(),
|
|
171
|
-
$randomIp: faker.internet.ip(),
|
|
172
|
-
$randomHexColor: faker.color.rgb({ format: "hex", casing: "lower" })
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
function interpolate(str, vars) {
|
|
176
|
-
return str.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
|
|
177
|
-
const trimmed = key.trim();
|
|
178
|
-
if (trimmed in vars) return vars[trimmed];
|
|
179
|
-
if (_exprContext && (trimmed.includes(".") || trimmed.includes("("))) {
|
|
180
|
-
try {
|
|
181
|
-
const result = vm__namespace.runInNewContext(trimmed, _exprContext);
|
|
182
|
-
if (result !== void 0 && result !== null) return String(result);
|
|
183
|
-
} catch {
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return match;
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
function buildUrl(baseUrl, params, vars) {
|
|
190
|
-
const templateTokens = /* @__PURE__ */ new Set();
|
|
191
|
-
baseUrl.replace(/\{\{([^}]+)\}\}/g, (_m, name) => {
|
|
192
|
-
templateTokens.add(String(name).trim());
|
|
193
|
-
return "";
|
|
194
|
-
});
|
|
195
|
-
const enabled = (params ?? []).filter((p) => p.enabled && p.key);
|
|
196
|
-
const pathRows = [];
|
|
197
|
-
const queryRows = [];
|
|
198
|
-
for (const p of enabled) {
|
|
199
|
-
const isPath = p.paramType === "path" || templateTokens.has(p.key);
|
|
200
|
-
if (isPath) pathRows.push(p);
|
|
201
|
-
else queryRows.push(p);
|
|
202
|
-
}
|
|
203
|
-
const mergedVars = pathRows.length ? {
|
|
204
|
-
...vars,
|
|
205
|
-
...Object.fromEntries(pathRows.map((p) => [p.key, interpolate(p.value, vars)]))
|
|
206
|
-
} : vars;
|
|
207
|
-
const url = interpolate(baseUrl, mergedVars);
|
|
208
|
-
if (!queryRows.length) return url;
|
|
209
|
-
const sep = url.includes("?") ? "&" : "?";
|
|
210
|
-
const qs = queryRows.map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
|
|
211
|
-
return url + sep + qs;
|
|
212
|
-
}
|
|
213
|
-
async function buildEnvVars(environment) {
|
|
214
|
-
const vars = {};
|
|
215
|
-
if (!environment) return vars;
|
|
216
|
-
const masterKey = process.env["API_SPECTOR_MASTER_KEY"];
|
|
217
|
-
for (const v of environment.variables) {
|
|
218
|
-
if (!v.enabled) continue;
|
|
219
|
-
if (v.envRef) {
|
|
220
|
-
const envValue = process.env[v.envRef];
|
|
221
|
-
if (envValue !== void 0) vars[v.key] = envValue;
|
|
222
|
-
} else if (v.secret && v.secretEncrypted && v.secretSalt && v.secretIv) {
|
|
223
|
-
if (masterKey) {
|
|
224
|
-
try {
|
|
225
|
-
vars[v.key] = decryptSecret(v.secretEncrypted, v.secretSalt, v.secretIv, masterKey);
|
|
226
|
-
} catch {
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (vars[v.key] === void 0 && process.env[v.key] !== void 0) {
|
|
230
|
-
vars[v.key] = process.env[v.key];
|
|
231
|
-
}
|
|
232
|
-
} else if (v.secret) {
|
|
233
|
-
if (process.env[v.key] !== void 0) {
|
|
234
|
-
vars[v.key] = process.env[v.key];
|
|
235
|
-
}
|
|
236
|
-
} else {
|
|
237
|
-
vars[v.key] = v.value;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
return vars;
|
|
241
|
-
}
|
|
242
|
-
function mergeVars(envVars, collectionVars, globals2, localVars = {}, dynamicVars = {}) {
|
|
243
|
-
return { ...dynamicVars, ...globals2, ...collectionVars, ...envVars, ...localVars };
|
|
244
|
-
}
|
|
245
81
|
function xmlFindAll(node, tag, nth) {
|
|
246
82
|
const results = [];
|
|
247
83
|
const siblings = Array.from(node.childNodes).filter((c) => c.nodeType === 1 && c.tagName === tag);
|
|
@@ -600,156 +436,6 @@ async function runScript(code, ctx, timeoutMs = 5e3) {
|
|
|
600
436
|
updatedLocalVars: localVarsCopy
|
|
601
437
|
};
|
|
602
438
|
}
|
|
603
|
-
async function buildAuthHeaders(auth, vars) {
|
|
604
|
-
const headers = {};
|
|
605
|
-
if (auth.type === "bearer") {
|
|
606
|
-
let token = auth.token ?? "";
|
|
607
|
-
if (!token && auth.tokenSecretRef) token = await getSecret(auth.tokenSecretRef) ?? "";
|
|
608
|
-
token = interpolate(token, vars);
|
|
609
|
-
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
610
|
-
}
|
|
611
|
-
if (auth.type === "basic") {
|
|
612
|
-
let password = auth.password ?? "";
|
|
613
|
-
if (!password && auth.passwordSecretRef) password = await getSecret(auth.passwordSecretRef) ?? "";
|
|
614
|
-
password = interpolate(password, vars);
|
|
615
|
-
const username = interpolate(auth.username ?? "", vars);
|
|
616
|
-
headers["Authorization"] = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
617
|
-
}
|
|
618
|
-
if (auth.type === "apikey" && auth.apiKeyIn === "header") {
|
|
619
|
-
let value = auth.apiKeyValue ?? "";
|
|
620
|
-
if (!value && auth.apiKeySecretRef) value = await getSecret(auth.apiKeySecretRef) ?? "";
|
|
621
|
-
value = interpolate(value, vars);
|
|
622
|
-
headers[auth.apiKeyName ?? "X-API-Key"] = value;
|
|
623
|
-
}
|
|
624
|
-
if (auth.type === "oauth2") {
|
|
625
|
-
const now = Date.now();
|
|
626
|
-
if (auth.oauth2CachedToken && auth.oauth2TokenExpiry && auth.oauth2TokenExpiry > now + 5e3) {
|
|
627
|
-
headers["Authorization"] = `Bearer ${auth.oauth2CachedToken}`;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
return headers;
|
|
631
|
-
}
|
|
632
|
-
async function buildApiKeyParam(auth, vars) {
|
|
633
|
-
if (auth.type !== "apikey" || auth.apiKeyIn !== "query") return null;
|
|
634
|
-
let value = auth.apiKeyValue ?? "";
|
|
635
|
-
if (!value && auth.apiKeySecretRef) value = await getSecret(auth.apiKeySecretRef) ?? "";
|
|
636
|
-
value = interpolate(value, vars);
|
|
637
|
-
return { key: auth.apiKeyName ?? "apikey", value };
|
|
638
|
-
}
|
|
639
|
-
function parseDigestChallenge(wwwAuth) {
|
|
640
|
-
const extract = (key) => {
|
|
641
|
-
const m = new RegExp(`${key}="([^"]*)"`, "i").exec(wwwAuth);
|
|
642
|
-
return m ? m[1] : "";
|
|
643
|
-
};
|
|
644
|
-
const extractUnquoted = (key) => {
|
|
645
|
-
const m = new RegExp(`${key}=([^,\\s]+)`, "i").exec(wwwAuth);
|
|
646
|
-
return m ? m[1] : "";
|
|
647
|
-
};
|
|
648
|
-
return {
|
|
649
|
-
realm: extract("realm"),
|
|
650
|
-
nonce: extract("nonce"),
|
|
651
|
-
qop: extract("qop") || extractUnquoted("qop") || void 0,
|
|
652
|
-
algorithm: extract("algorithm") || extractUnquoted("algorithm") || "MD5",
|
|
653
|
-
opaque: extract("opaque") || void 0
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
function md5(s) {
|
|
657
|
-
return crypto.createHash("md5").update(s).digest("hex");
|
|
658
|
-
}
|
|
659
|
-
function buildDigestAuthHeader(challenge, username, password, method, uri) {
|
|
660
|
-
const { realm, nonce, qop, algorithm, opaque } = challenge;
|
|
661
|
-
const algo = (algorithm ?? "MD5").toUpperCase();
|
|
662
|
-
const ha1 = algo === "MD5-SESS" ? md5(`${md5(`${username}:${realm}:${password}`)}:${nonce}:`) : md5(`${username}:${realm}:${password}`);
|
|
663
|
-
const ha2 = md5(`${method}:${uri}`);
|
|
664
|
-
let response;
|
|
665
|
-
let nc;
|
|
666
|
-
let cnonce;
|
|
667
|
-
if (qop === "auth" || qop === "auth-int") {
|
|
668
|
-
nc = "00000001";
|
|
669
|
-
cnonce = crypto.randomBytes(8).toString("hex");
|
|
670
|
-
response = md5(`${ha1}:${nonce}:${nc}:${cnonce}:${qop}:${ha2}`);
|
|
671
|
-
} else {
|
|
672
|
-
response = md5(`${ha1}:${nonce}:${ha2}`);
|
|
673
|
-
}
|
|
674
|
-
let header = `Digest username="${username}", realm="${realm}", nonce="${nonce}", uri="${uri}", response="${response}"`;
|
|
675
|
-
if (qop) header += `, qop=${qop}`;
|
|
676
|
-
if (nc) header += `, nc=${nc}`;
|
|
677
|
-
if (cnonce) header += `, cnonce="${cnonce}"`;
|
|
678
|
-
if (opaque) header += `, opaque="${opaque}"`;
|
|
679
|
-
if (algo !== "MD5") header += `, algorithm=${algo}`;
|
|
680
|
-
return header;
|
|
681
|
-
}
|
|
682
|
-
async function performDigestAuth(url, method, auth, vars, fetchFn) {
|
|
683
|
-
const probeResp = await fetchFn(url, { method, headers: {} });
|
|
684
|
-
if (probeResp.status !== 401) return null;
|
|
685
|
-
const wwwAuth = probeResp.headers.get("www-authenticate") ?? "";
|
|
686
|
-
if (!wwwAuth.toLowerCase().startsWith("digest")) return null;
|
|
687
|
-
const challenge = parseDigestChallenge(wwwAuth);
|
|
688
|
-
let password = auth.password ?? "";
|
|
689
|
-
if (!password && auth.passwordSecretRef) password = await getSecret(auth.passwordSecretRef) ?? "";
|
|
690
|
-
password = interpolate(password, vars);
|
|
691
|
-
const username = interpolate(auth.username ?? "", vars);
|
|
692
|
-
let uri = "/";
|
|
693
|
-
try {
|
|
694
|
-
uri = new URL(url).pathname + (new URL(url).search ?? "");
|
|
695
|
-
} catch {
|
|
696
|
-
}
|
|
697
|
-
return buildDigestAuthHeader(challenge, username, password, method, uri);
|
|
698
|
-
}
|
|
699
|
-
async function performNtlmRequest(_url, _method, _auth, _vars) {
|
|
700
|
-
throw new Error(
|
|
701
|
-
'NTLM auth is not yet implemented. Add "httpntlm" to package.json dependencies and implement performNtlmRequest in auth-builder.ts.'
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
async function fetchOAuth2Token(auth, vars) {
|
|
705
|
-
const flow = auth.oauth2Flow ?? "client_credentials";
|
|
706
|
-
if (flow === "authorization_code") {
|
|
707
|
-
throw new Error("authorization_code flow requires the oauth2:startFlow IPC call from the renderer.");
|
|
708
|
-
}
|
|
709
|
-
if (flow === "implicit") {
|
|
710
|
-
throw new Error("implicit flow cannot be performed server-side — tokens must be obtained via the browser redirect.");
|
|
711
|
-
}
|
|
712
|
-
const tokenUrl = interpolate(auth.oauth2TokenUrl ?? "", vars);
|
|
713
|
-
if (!tokenUrl) throw new Error("OAuth 2.0: tokenUrl is required.");
|
|
714
|
-
const clientId = interpolate(auth.oauth2ClientId ?? "", vars);
|
|
715
|
-
let clientSecret = auth.oauth2ClientSecret ?? "";
|
|
716
|
-
if (!clientSecret && auth.oauth2ClientSecretRef) {
|
|
717
|
-
clientSecret = await getSecret(auth.oauth2ClientSecretRef) ?? "";
|
|
718
|
-
}
|
|
719
|
-
clientSecret = interpolate(clientSecret, vars);
|
|
720
|
-
const params = new URLSearchParams();
|
|
721
|
-
params.set("grant_type", flow === "password" ? "password" : "client_credentials");
|
|
722
|
-
params.set("client_id", clientId);
|
|
723
|
-
params.set("client_secret", clientSecret);
|
|
724
|
-
if (auth.oauth2Scopes) params.set("scope", auth.oauth2Scopes);
|
|
725
|
-
if (flow === "password") {
|
|
726
|
-
let password = auth.password ?? "";
|
|
727
|
-
if (!password && auth.passwordSecretRef) password = await getSecret(auth.passwordSecretRef) ?? "";
|
|
728
|
-
password = interpolate(password, vars);
|
|
729
|
-
params.set("username", interpolate(auth.username ?? "", vars));
|
|
730
|
-
params.set("password", password);
|
|
731
|
-
}
|
|
732
|
-
const { fetch: nodeFetch } = await import("undici");
|
|
733
|
-
const resp = await nodeFetch(tokenUrl, {
|
|
734
|
-
method: "POST",
|
|
735
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
736
|
-
body: params.toString()
|
|
737
|
-
});
|
|
738
|
-
if (!resp.ok) {
|
|
739
|
-
const body = await resp.text();
|
|
740
|
-
throw new Error(`OAuth 2.0 token request failed (${resp.status}): ${body}`);
|
|
741
|
-
}
|
|
742
|
-
const json = await resp.json();
|
|
743
|
-
const accessToken = String(json["access_token"] ?? "");
|
|
744
|
-
if (!accessToken) throw new Error("OAuth 2.0: token response missing access_token.");
|
|
745
|
-
const expiresIn = Number(json["expires_in"] ?? 3600);
|
|
746
|
-
const expiresAt = Date.now() + expiresIn * 1e3;
|
|
747
|
-
return {
|
|
748
|
-
accessToken,
|
|
749
|
-
expiresAt,
|
|
750
|
-
refreshToken: json["refresh_token"] ? String(json["refresh_token"]) : void 0
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
439
|
function buildProxyUri(proxy) {
|
|
754
440
|
const raw = proxy.url.trim();
|
|
755
441
|
if (!raw) throw new Error("Proxy URL is empty");
|
|
@@ -972,7 +658,7 @@ function registerRequestHandler(ipc) {
|
|
|
972
658
|
const start = Date.now();
|
|
973
659
|
const liveGlobals = getGlobals();
|
|
974
660
|
const mergedGlobals = { ...payloadGlobals, ...liveGlobals };
|
|
975
|
-
const envVars = await buildEnvVars(environment);
|
|
661
|
+
const envVars = await authBuilder.buildEnvVars(environment);
|
|
976
662
|
let localVars = {};
|
|
977
663
|
const decryptionWarnings = [];
|
|
978
664
|
if (environment) {
|
|
@@ -986,14 +672,14 @@ function registerRequestHandler(ipc) {
|
|
|
986
672
|
}
|
|
987
673
|
}
|
|
988
674
|
}
|
|
989
|
-
const dynamicVars = await buildDynamicVars();
|
|
990
|
-
let vars = mergeVars(envVars, collectionVars, mergedGlobals, localVars, dynamicVars);
|
|
675
|
+
const dynamicVars = await authBuilder.buildDynamicVars();
|
|
676
|
+
let vars = authBuilder.mergeVars(envVars, collectionVars, mergedGlobals, localVars, dynamicVars);
|
|
991
677
|
let preScriptMeta = { consoleOutput: [] };
|
|
992
678
|
let updatedCollectionVars = { ...collectionVars };
|
|
993
679
|
let updatedEnvVars = { ...envVars };
|
|
994
680
|
let updatedGlobals = { ...mergedGlobals };
|
|
995
681
|
if (req.preRequestScript?.trim()) {
|
|
996
|
-
const result = await runScript(interpolate(req.preRequestScript, vars), {
|
|
682
|
+
const result = await runScript(authBuilder.interpolate(req.preRequestScript, vars), {
|
|
997
683
|
envVars: { ...envVars },
|
|
998
684
|
collectionVars: { ...collectionVars },
|
|
999
685
|
globals: { ...mergedGlobals },
|
|
@@ -1006,11 +692,11 @@ function registerRequestHandler(ipc) {
|
|
|
1006
692
|
updatedGlobals = result.updatedGlobals;
|
|
1007
693
|
patchGlobals(result.updatedGlobals);
|
|
1008
694
|
await persistGlobals();
|
|
1009
|
-
vars = mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars);
|
|
695
|
+
vars = authBuilder.mergeVars(updatedEnvVars, updatedCollectionVars, updatedGlobals, localVars, dynamicVars);
|
|
1010
696
|
}
|
|
1011
697
|
let response;
|
|
1012
698
|
let sentRequest = { method: req.method, url: "", headers: {} };
|
|
1013
|
-
const resolvedUrl = buildUrl(req.url, req.params, vars);
|
|
699
|
+
const resolvedUrl = authBuilder.buildUrl(req.url, req.params, vars);
|
|
1014
700
|
const secretValues = /* @__PURE__ */ new Set();
|
|
1015
701
|
if (environment) {
|
|
1016
702
|
for (const v of environment.variables) {
|
|
@@ -1047,13 +733,13 @@ function registerRequestHandler(ipc) {
|
|
|
1047
733
|
const tokenMissing = !req.auth.oauth2CachedToken;
|
|
1048
734
|
const tokenExpired = req.auth.oauth2TokenExpiry ? req.auth.oauth2TokenExpiry <= now + 5e3 : true;
|
|
1049
735
|
if (tokenMissing || tokenExpired) {
|
|
1050
|
-
const result = await fetchOAuth2Token(req.auth, vars);
|
|
736
|
+
const result = await authBuilder.fetchOAuth2Token(req.auth, vars);
|
|
1051
737
|
req.auth.oauth2CachedToken = result.accessToken;
|
|
1052
738
|
req.auth.oauth2TokenExpiry = result.expiresAt;
|
|
1053
739
|
}
|
|
1054
740
|
}
|
|
1055
|
-
const authHeaders = await buildAuthHeaders(req.auth, vars);
|
|
1056
|
-
const apiKeyParam = await buildApiKeyParam(req.auth, vars);
|
|
741
|
+
const authHeaders = await authBuilder.buildAuthHeaders(req.auth, vars);
|
|
742
|
+
const apiKeyParam = await authBuilder.buildApiKeyParam(req.auth, vars);
|
|
1057
743
|
let finalUrl = resolvedUrl;
|
|
1058
744
|
if (apiKeyParam) {
|
|
1059
745
|
const sep = finalUrl.includes("?") ? "&" : "?";
|
|
@@ -1063,7 +749,7 @@ function registerRequestHandler(ipc) {
|
|
|
1063
749
|
const h = new undici.Headers();
|
|
1064
750
|
for (const header of req.headers) {
|
|
1065
751
|
if (header.enabled && header.key) {
|
|
1066
|
-
h.set(interpolate(header.key, vars), interpolate(header.value, vars));
|
|
752
|
+
h.set(authBuilder.interpolate(header.key, vars), authBuilder.interpolate(header.value, vars));
|
|
1067
753
|
}
|
|
1068
754
|
}
|
|
1069
755
|
for (const [k, v] of Object.entries(authHeaders)) h.set(k, v);
|
|
@@ -1071,18 +757,18 @@ function registerRequestHandler(ipc) {
|
|
|
1071
757
|
};
|
|
1072
758
|
let body;
|
|
1073
759
|
if (req.body.mode === "json" && req.body.json) {
|
|
1074
|
-
body = interpolate(req.body.json, vars);
|
|
760
|
+
body = authBuilder.interpolate(req.body.json, vars);
|
|
1075
761
|
} else if (req.body.mode === "form" && req.body.form) {
|
|
1076
|
-
body = req.body.form.filter((p) => p.enabled && p.key).map((p) => `${encodeURIComponent(interpolate(p.key, vars))}=${encodeURIComponent(interpolate(p.value, vars))}`).join("&");
|
|
762
|
+
body = req.body.form.filter((p) => p.enabled && p.key).map((p) => `${encodeURIComponent(authBuilder.interpolate(p.key, vars))}=${encodeURIComponent(authBuilder.interpolate(p.value, vars))}`).join("&");
|
|
1077
763
|
} else if (req.body.mode === "raw" && req.body.raw) {
|
|
1078
|
-
body = interpolate(req.body.raw, vars);
|
|
764
|
+
body = authBuilder.interpolate(req.body.raw, vars);
|
|
1079
765
|
} else if (req.body.mode === "graphql" && req.body.graphql) {
|
|
1080
766
|
const gql = req.body.graphql;
|
|
1081
|
-
const gqlBody = { query: interpolate(gql.query, vars) };
|
|
767
|
+
const gqlBody = { query: authBuilder.interpolate(gql.query, vars) };
|
|
1082
768
|
const rawVars = gql.variables?.trim();
|
|
1083
769
|
if (rawVars) {
|
|
1084
770
|
try {
|
|
1085
|
-
gqlBody.variables = JSON.parse(interpolate(rawVars, vars));
|
|
771
|
+
gqlBody.variables = JSON.parse(authBuilder.interpolate(rawVars, vars));
|
|
1086
772
|
} catch {
|
|
1087
773
|
}
|
|
1088
774
|
}
|
|
@@ -1090,7 +776,7 @@ function registerRequestHandler(ipc) {
|
|
|
1090
776
|
body = JSON.stringify(gqlBody);
|
|
1091
777
|
} else if (req.body.mode === "soap" && req.body.soap) {
|
|
1092
778
|
const soap = req.body.soap;
|
|
1093
|
-
body = interpolate(soap.envelope, vars);
|
|
779
|
+
body = authBuilder.interpolate(soap.envelope, vars);
|
|
1094
780
|
}
|
|
1095
781
|
const methodHasBody = !["GET", "HEAD"].includes(req.method);
|
|
1096
782
|
const doFetch = async (overrideHeaders) => {
|
|
@@ -1120,7 +806,7 @@ function registerRequestHandler(ipc) {
|
|
|
1120
806
|
};
|
|
1121
807
|
let fetchResp;
|
|
1122
808
|
if (req.auth.type === "ntlm") {
|
|
1123
|
-
await performNtlmRequest(finalUrl, req.method, req.auth, vars);
|
|
809
|
+
await authBuilder.performNtlmRequest(finalUrl, req.method, req.auth, vars);
|
|
1124
810
|
fetchResp = await doFetch();
|
|
1125
811
|
} else if (req.auth.type === "digest") {
|
|
1126
812
|
const probeFetch = async (url, init) => {
|
|
@@ -1129,7 +815,7 @@ function registerRequestHandler(ipc) {
|
|
|
1129
815
|
dispatcher
|
|
1130
816
|
});
|
|
1131
817
|
};
|
|
1132
|
-
const digestHeader = await performDigestAuth(finalUrl, req.method, req.auth, vars, probeFetch);
|
|
818
|
+
const digestHeader = await authBuilder.performDigestAuth(finalUrl, req.method, req.auth, vars, probeFetch);
|
|
1133
819
|
const h = buildHeaders();
|
|
1134
820
|
if (digestHeader) h.set("Authorization", digestHeader);
|
|
1135
821
|
fetchResp = await doFetch(h);
|
|
@@ -1176,7 +862,7 @@ function registerRequestHandler(ipc) {
|
|
|
1176
862
|
let postConsole = [];
|
|
1177
863
|
let postError;
|
|
1178
864
|
if (req.postRequestScript?.trim() && !response.error) {
|
|
1179
|
-
const result = await runScript(interpolate(req.postRequestScript, vars), {
|
|
865
|
+
const result = await runScript(authBuilder.interpolate(req.postRequestScript, vars), {
|
|
1180
866
|
envVars: { ...updatedEnvVars },
|
|
1181
867
|
collectionVars: { ...updatedCollectionVars },
|
|
1182
868
|
globals: { ...updatedGlobals },
|
|
@@ -1291,29 +977,17 @@ function resolveInheritedAuthAndHeaders(requestId, collection) {
|
|
|
1291
977
|
}
|
|
1292
978
|
return { auth: inheritedAuth, headers: inheritedHeaders };
|
|
1293
979
|
}
|
|
1294
|
-
exports.buildAuthHeaders = buildAuthHeaders;
|
|
1295
980
|
exports.buildDispatcher = buildDispatcher;
|
|
1296
|
-
exports.buildDynamicVars = buildDynamicVars;
|
|
1297
|
-
exports.buildEnvVars = buildEnvVars;
|
|
1298
981
|
exports.buildSchemaTestResults = buildSchemaTestResults;
|
|
1299
|
-
exports.buildUrl = buildUrl;
|
|
1300
982
|
exports.collectTagged = collectTagged;
|
|
1301
|
-
exports.fetchOAuth2Token = fetchOAuth2Token;
|
|
1302
983
|
exports.getAllApplicableHooks = getAllApplicableHooks;
|
|
1303
984
|
exports.getGlobals = getGlobals;
|
|
1304
|
-
exports.getSecret = getSecret;
|
|
1305
|
-
exports.initSecretStore = initSecretStore;
|
|
1306
|
-
exports.interpolate = interpolate;
|
|
1307
985
|
exports.loadGlobals = loadGlobals;
|
|
1308
986
|
exports.maskHeaders = maskHeaders;
|
|
1309
987
|
exports.maskPii = maskPii;
|
|
1310
|
-
exports.mergeVars = mergeVars;
|
|
1311
988
|
exports.patchGlobals = patchGlobals;
|
|
1312
|
-
exports.performDigestAuth = performDigestAuth;
|
|
1313
|
-
exports.performNtlmRequest = performNtlmRequest;
|
|
1314
989
|
exports.persistGlobals = persistGlobals;
|
|
1315
990
|
exports.registerRequestHandler = registerRequestHandler;
|
|
1316
|
-
exports.registerSecretHandlers = registerSecretHandlers;
|
|
1317
991
|
exports.resolveInheritedAuthAndHeaders = resolveInheritedAuthAndHeaders;
|
|
1318
992
|
exports.runScript = runScript;
|
|
1319
993
|
exports.setGlobals = setGlobals;
|