UNPKG

cumulocity-cypress

Version:
1,010 lines (997 loc) 37 kB
'use strict'; var _$2 = require('lodash'); var client = require('@c8y/client'); var setCookieParser = require('set-cookie-parser'); var libCookie = require('cookie'); var semver = require('semver'); var fetch = require('cross-fetch'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var ___namespace = /*#__PURE__*/_interopNamespaceDefault(_$2); var setCookieParser__namespace = /*#__PURE__*/_interopNamespaceDefault(setCookieParser); var libCookie__namespace = /*#__PURE__*/_interopNamespaceDefault(libCookie); var semver__namespace = /*#__PURE__*/_interopNamespaceDefault(semver); function isURL(obj) { return obj instanceof URL; } function relativeURL(url) { try { const u = isURL(url) ? url : new URL(url); return u.pathname + u.search; } catch { return undefined; } } function removeBaseUrlFromString(url, baseUrl) { if (!url || !baseUrl) { return url; } let normalizedBaseUrl = _$2.clone(baseUrl); while (normalizedBaseUrl.endsWith("/")) { normalizedBaseUrl = normalizedBaseUrl.slice(0, -1); } let result = url.replace(normalizedBaseUrl, ""); if (_$2.isEmpty(result)) { result = "/"; } return result; } function normalizeUrl(url) { return url.replace(/\/+$/, ""); } function tenantUrl(baseUrl, tenant) { if (!baseUrl || !tenant) return undefined; try { const url = new URL(baseUrl); const hostComponents = url.host.split("."); if (hostComponents.length <= 2) { url.host = `${tenant}.${hostComponents.join(".")}`; } else { const instance = url.host.split(".")?.slice(1)?.join("."); url.host = `${tenant}.${instance}`; } return normalizeUrl(url.toString()); } catch { // no-op } return undefined; } /** * Checks if the given URL is an absolute URL. * @param url The URL to check. * @returns True if the URL is an absolute URL, false otherwise. */ function isAbsoluteURL(url) { if (!url || !_$2.isString(url) || _$2.isEmpty(url)) return false; return /^https?:\/\//i.test(url); } /** * Normalizes a URL to ensure it has a protocol and proper trailing slash. * If no protocol is present, HTTPS is added by default. * If the URL has no path component, a trailing slash is appended. * * @param url - The URL string to normalize * @returns The normalized URL with HTTPS protocol and trailing slash if appropriate, or undefined for invalid input */ function normalizeBaseUrl(url) { if (!url || !_$2.isString(url)) { return undefined; } const trimmedUrl = url.trim(); if (!trimmedUrl) { return undefined; } let normalizedUrl; // Check if URL already has a protocol if (/^https?:\/\//i.test(trimmedUrl)) { normalizedUrl = trimmedUrl; } else { // Add https:// if no protocol is present normalizedUrl = `https://${trimmedUrl}`; } try { const urlObj = new URL(normalizedUrl); // remove all components other than protocol, host normalizedUrl = `${urlObj.protocol}//${urlObj.host}`; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); throw new Error(`Failed to normalize base url ${url}. ${errorMessage}`); } return normalizedUrl; } /** * Converts the given URL to a string. * @param url The URL or RequestInfo to convert. * @returns The URL as a string. */ function toUrlString(url) { if (_$2.isString(url)) { return url; } else if (url instanceof URL) { return url.toString(); } else if (url instanceof Request) { return url.url; } else { throw new Error(`Type for URL not supported. Expected URL, string or Request, but found $'{typeof url}}'.`); } } function safeStringify(obj, indent = 2) { let cache = []; const retVal = JSON.stringify(obj, (key, value) => typeof value === "object" && value !== null ? cache.includes(value) ? undefined : cache.push(value) && value : value, indent); cache = []; return retVal; } function sanitizeStringifiedObject(obj) { if (!_$2.isString(obj)) { return obj; } const regex = /((?:"password"|'password'|password|"token"|'token'|token)\s*:\s*["']?)(.*?)(["']|,|\s|}|$)/gi; return obj.replace(regex, "$1***$3"); } /** * Gets the case-sensitive path for a given case-insensitive path. The path is * assumed to be a dot-separated string. If the path is an array, it is assumed * to be a list of keys. * * @param obj The object to query * @param path The case-insensitive path to find * @returns The actual case-sensitive path if found, undefined otherwise */ function toSensitiveObjectKeyPath(obj, path) { if (!obj) return undefined; const inputStr = _$2.isArray(path) ? null : path; const keys = _$2.isArray(path) ? path.filter((k) => !_$2.isEmpty(k)) : path.split(/[.[\]]/g).filter((k) => !_$2.isEmpty(k)); let current = obj; const resolved = []; for (const key of keys) { if (current === null || current === undefined) return undefined; if (_$2.isArray(current)) { const index = parseInt(key); if (!isNaN(index)) { if (index >= 0 && index < current.length) { resolved.push(key); current = current[index]; } else { return undefined; // index out of bounds } } else if (current.length > 0 && _$2.isString(current[0])) { const matchedIndex = current.findIndex((item) => _$2.isString(item) && item.toLowerCase() === key.toLowerCase()); if (matchedIndex !== -1) { resolved.push(String(matchedIndex)); current = current[matchedIndex]; } else { return undefined; } } else if (current.length > 0 && _$2.isObjectLike(current[0])) { // For arrays of objects, resolve case through the first element so // the caller gets the correctly-cased key without needing an index. const matchingKey = Object.keys(current[0]).find((k) => k.toLowerCase() === key.toLowerCase()); if (matchingKey !== undefined) { resolved.push(matchingKey); current = current[0][matchingKey]; } else { return undefined; } } else { return undefined; } continue; } if (_$2.isObjectLike(current)) { const matchingKey = Object.keys(current).find((k) => k.toLowerCase() === key.toLowerCase()); if (matchingKey !== undefined) { resolved.push(matchingKey); current = current[matchingKey]; } else { return undefined; } } else { return undefined; } } // Fast path: array input or no brackets in input — plain dot-joined output if (!inputStr || !inputStr.includes("[")) return resolved.join("."); // Mirror bracket vs. dot notation from the input when building the output. // Walk the original string in parallel with the resolved keys: wherever the // input had `[key]` we emit `[resolvedKey]`, otherwise `.resolvedKey`. let result = ""; let pos = 0; for (let i = 0; i < resolved.length; i++) { // skip separators (dot after a `]`, or the `]` itself) while (pos < inputStr.length && (inputStr[pos] === "." || inputStr[pos] === "]")) pos++; const useBracket = inputStr[pos] === "["; if (useBracket) pos++; // skip `[` // skip past the key characters in the input while (pos < inputStr.length && inputStr[pos] !== "." && inputStr[pos] !== "[" && inputStr[pos] !== "]") pos++; if (i === 0) result = resolved[i]; else result += useBracket ? `[${resolved[i]}]` : `.${resolved[i]}`; } return result; } /** * Gets the value of a case-insensitive key path from an object. The path is * assumed to be a dot-separated string. If the path is an array, it is assumed * to be a list of keys. * * This function supports deep access to cookie and set-cookie headers, e.g. * `requestHeaders.cookie.authorization`. Cookie headers are parsed and the value * of the specified cookie is returned. If the cookie is not found, undefined is returned. * * @example * get_i(obj, "obj.key.token") * get_i(obj, ["obj", "key", "token"]) * get_i(obj, "obj.key[0].token") * get_i(obj, "obj.key.0.token") * get_i(obj, "requestHeaders.cookie.authorization") * get_i(obj, "requestHeaders.set-cookie.authorization") * * @param obj The object to query * @param keyPath The case-insensitive key path to find * @returns The value of the key path if found, undefined otherwise */ function get_i(obj, keyPath) { if (obj == null || keyPath == null) return undefined; // Handle case where obj itself is an array of strings with a single key lookup const keys = _$2.isArray(keyPath) ? keyPath.filter((k) => !_$2.isEmpty(k)) : keyPath.split(/[.[\]]/g).filter((k) => !_$2.isEmpty(k)); if (keys.length === 1 && _$2.isArray(obj) && obj.length > 0 && _$2.isString(obj[0])) { const matchedString = obj.find((item) => _$2.isString(item) && item.toLowerCase() === keys[0].toLowerCase()); if (matchedString !== undefined) { return matchedString; } } const sensitivePath = toSensitiveObjectKeyPath(obj, keyPath); let direct = undefined; // Try direct access first if we have a valid path if (sensitivePath != null) { direct = _$2.get(obj, sensitivePath); if (direct !== undefined) return direct; } // Handle cookie and set-cookie deep access, e.g. requestHeaders.cookie.authorization if (!keys || keys.length === 0) return undefined; const indexOfKey = (arr, val) => arr.findIndex((k) => k.toLowerCase() === val.toLowerCase()); const cookieIdx = indexOfKey(keys, "cookie"); const setCookieIdx = indexOfKey(keys, "set-cookie"); // Helper to resolve the real path up to a certain index (inclusive) const resolvePathUpTo = (idx) => { const part = keys.slice(0, idx + 1); return toSensitiveObjectKeyPath(obj, part) ?? part.join("."); }; // requestHeaders.cookie.<name> if (cookieIdx >= 0) { const parentPath = resolvePathUpTo(cookieIdx); const cookieHeader = parentPath ? _$2.get(obj, parentPath) : undefined; const cookieName = keys[cookieIdx + 1]; if (cookieHeader == null) return undefined; if (!cookieName) return cookieHeader; // return full header if no name // Parse Cookie header string into key/value if (_$2.isString(cookieHeader)) { const parsed = libCookie__namespace.parse(cookieHeader); const matchKey = Object.keys(parsed).find((k) => k.toLowerCase() === cookieName.toLowerCase()); return matchKey ? parsed[matchKey] : undefined; } return undefined; } // headers.set-cookie.<name> if (setCookieIdx >= 0) { const parentPath = resolvePathUpTo(setCookieIdx); const setCookieHeader = parentPath ? _$2.get(obj, parentPath) : undefined; const cookieName = keys[setCookieIdx + 1]; if (setCookieHeader == null) return undefined; if (!cookieName) return setCookieHeader; // return full header if no name // Parse Set-Cookie header (array or string) const headerInput = _$2.isString(setCookieHeader) ? setCookieParser__namespace.splitCookiesString(setCookieHeader) : setCookieHeader; const cookies = setCookieParser__namespace.parse(headerInput, { decodeValues: false, }); const found = (cookies || []).find((c) => c?.name?.toLowerCase() === cookieName.toLowerCase()); return found?.value; } // Handle arrays of strings with case-insensitive matching // For paths like "headers.authorization" where headers is ["Content-Type", "Authorization"] for (let i = 0; i < keys.length; i++) { const parentPath = resolvePathUpTo(i); const parentValue = parentPath ? _$2.get(obj, parentPath) : undefined; if (_$2.isArray(parentValue) && parentValue.length > 0 && _$2.isString(parentValue[0])) { const searchKey = keys[i + 1]; if (searchKey) { const index = parseInt(searchKey); if (isNaN(index)) { // Non-numeric key, try to find case-insensitive match in string array const matchedString = parentValue.find((item) => _$2.isString(item) && item.toLowerCase() === searchKey.toLowerCase()); // Only return a match when this segment is the final path segment if (matchedString !== undefined && i + 1 === keys.length - 1) { return matchedString; } } } } } return direct; } /** * Converts a value to an array. If the value is an array, it is returned as is. * @param value The value to convert to an array * @returns The value as an array if it is not already an array */ function to_array(value) { if (value == null) return undefined; if (_$2.isArray(value)) return value; return [value]; } /** * Converts a string value to a boolean. Supported values are "true", "false", "1", and "0". * @param input The input string to convert to a boolean * @param defaultValue The default value to return if the input is not a valid boolean string * @returns The boolean value of the input string or the default value if the input is not a valid boolean string */ function to_boolean(input, defaultValue) { if (input == null || !_$2.isString(input)) return defaultValue; const booleanString = input.toString().toLowerCase(); if (booleanString == "true" || booleanString === "1") return true; if (booleanString == "false" || booleanString === "0") return false; return defaultValue; } /// <reference types="cypress" /> const C8yPactAuthObjectKeys = [ "userAlias", "user", "type", ]; /** * Checks if the given object is a C8yAuthOptions. * * @param obj The object to check. * @param options Options to check for additional properties. * @returns True if the object is a C8yAuthOptions, false otherwise. */ function isAuthOptions(obj) { return (_$2.isObjectLike(obj) && (("user" in obj && "password" in obj) || "token" in obj)); } // new function to convert C8yAuthOptions to IAuthentication function toC8yAuthentication(obj) { if (!obj || !_$2.isObjectLike(obj)) { return undefined; } if (_$2.get(obj, "getFetchOptions")) { return obj; } if (!isAuthOptions(obj)) { return undefined; } if (obj.token) { return new client.BearerAuth(obj.token); } else if (obj.user && obj.password) { return new client.BasicAuth({ user: obj.user, password: obj.password, tenant: obj.tenant, }); } return undefined; } // map from case insensitive auth type to C8yAuthOptionType function getAuthType(auth) { const type = _$2.isString(auth) ? auth.toLowerCase() : auth?.type?.toLowerCase(); if (type === "bearerauth") { return "BearerAuth"; } if (type === "basicauth") { return "BasicAuth"; } if (type === "cookieauth") { return "CookieAuth"; } return undefined; } function hasAuthentication(client) { if (!client) return false; const fetchClient = _$2.get(client, "_client.core") ?? _$2.get(client, "core") ?? client; const getFetchOptionsFn = _$2.get(fetchClient, "getFetchOptions"); if (_$2.isFunction(getFetchOptionsFn)) { const options = getFetchOptionsFn.apply(fetchClient); if (!options) return false; if (get_i(options, "headers.X-XSRF-TOKEN")) return true; if (get_i(options, "headers.authorization")) return true; } if (_$2.get(fetchClient, "_auth")) return true; return false; } function toPactAuthObject(obj) { return _$2.pick(obj, C8yPactAuthObjectKeys); } function isPactAuthObject(obj) { return (_$2.isObjectLike(obj) && ("user" in obj || "token" in obj) && ("userAlias" in obj || "type" in obj || "token" in obj) && Object.keys(obj).every((key) => ["token", ...C8yPactAuthObjectKeys].includes(key))); } function normalizeAuthHeaders(headers) { // required to fix inconsistencies between c8yclient and interceptions // using lowercase and uppercase. fix here. const xsrfTokenHeader = Object.keys(headers || {}).find((key) => key.toLowerCase() === "x-xsrf-token"); const authorizationHeader = Object.keys(headers || {}).find((key) => key.toLowerCase() === "authorization"); if (xsrfTokenHeader && xsrfTokenHeader !== "X-XSRF-TOKEN") { headers["X-XSRF-TOKEN"] = headers[xsrfTokenHeader]; delete headers[xsrfTokenHeader]; } if (authorizationHeader && authorizationHeader !== "Authorization") { headers["Authorization"] = headers[authorizationHeader]; delete headers[authorizationHeader]; } return headers; } function getAuthOptionsFromEnv(env) { if (env == null || !_$2.isObjectLike(env)) { return undefined; } // check first environment variables const jwtToken = env["C8Y_TOKEN"]; let tokenAuth = undefined; try { const authFromToken = getAuthOptionsFromJWT(jwtToken); if (authFromToken) { tokenAuth = authWithTenant(env, authFromToken); } } catch { // ignore errors from extractTokensFromJWT // this is expected if the token is not a valid JWT } const user = env[`C8Y_USERNAME`] ?? env[`C8Y_USER`]; const password = env[`C8Y_PASSWORD`]; let basicAuth = undefined; if (!_$2.isEmpty(user) && !_$2.isEmpty(password)) { basicAuth = authWithTenant(env, { user, password, }); } if (!tokenAuth && !basicAuth) { return undefined; } return { ...(basicAuth ?? {}), ...(tokenAuth ?? {}) }; } function authWithTenant(env, options) { if (env == null || !_$2.isObjectLike(env)) { return options; } const tenant = env[`C8Y_TENANT`]; if (tenant && !options?.tenant) { _$2.extend(options, { tenant }); } return options; } function getAuthOptionsFromBasicAuthHeader(authHeader) { if (!authHeader || !_$2.isString(authHeader) || !authHeader.startsWith("Basic ")) { return undefined; } const base64Credentials = authHeader.slice("Basic ".length); const credentials = decodeBase64(base64Credentials); const components = credentials.split(":"); if (!components || components.length < 2) { return undefined; } return { user: components[0], password: components.slice(1).join(":") }; } /** * Extracts the authentication options from a JWT token. * @param jwtToken The JWT token to extract the authentication options from. * @returns The extracted authentication options. */ function getAuthOptionsFromJWT(jwtToken) { try { const payload = JSON.parse(atob(jwtToken.split(".")[1])); // Remove all characters not valid in JWT tokens (base64url: A-Z, a-z, 0-9, -, _, .) const cleanedToken = jwtToken?.replace(/[^A-Za-z0-9\-_.]/g, ""); return { token: cleanedToken, xsrfToken: payload.xsrfToken, tenant: payload.ten, user: payload.sub, baseUrl: normalizeBaseUrl(payload.aud ?? payload.iss), }; } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Failed to decode JWT token: ${message}`); } } /** * Extracts the tenant from the basic auth object. * @param auth The basic auth object containing the user property. * @returns The tenant or undefined if not found. */ function tenantFromBasicAuth(auth) { if (_$2.isString(auth)) { auth = { user: auth }; } if (!auth || !_$2.isObjectLike(auth) || !auth.user) return undefined; const components = auth.user.split("/"); if (!components || components.length < 2 || _$2.isEmpty(components[1]) || _$2.isEmpty(components[0])) return undefined; return components[0]; } function encodeBase64(str) { if (!str) return ""; let encoded; if (typeof Buffer !== "undefined") { encoded = Buffer.from(str).toString("base64"); } else { encoded = btoa(str); } return encoded; } function decodeBase64(base64) { if (!base64) return ""; let decoded; if (typeof Buffer !== "undefined") { decoded = Buffer.from(base64, "base64").toString("utf-8"); } else { decoded = atob(base64); } return decoded; } const _$1 = _$2 || ___namespace; /** * Checks if the given version satisfies the requirements provided as an array of semver ranges. * If no required ranges are provided or range is empty, `true` is returned. * @param version - The version to check as a string or SemVer object. * @param requires - The required versions as semver ranges or `null` to allow version without specifying a range. * @returns `true` if the version satisfies the requirements, `false` otherwise. */ function isVersionSatisfyingRequirements(version, requires) { if (!requires || !_$1.isArrayLike(requires) || _$1.isEmpty(requires)) return true; if (requires.length === 1 && _$1.first(requires) == null) return true; let result = true; if (version != null) { const requiredRanges = getRangesSatisfyingVersion(version, requires); result = !_$1.isEmpty(requiredRanges); } else { // null is a special placeholder to mark the test to be executed if NO system version // is configured. Used for example for mocked tests with cy.intercept. result = requires?.includes(null); } return result; } /** * Returns the required semver ranges that are satisfied by the given version. * @param version - The version to check as a string or SemVer object. * @param requires - The required versions as semver ranges or `null` to allow version without specifying a range. * @returns The ranges that are satisfied by the version. */ function getRangesSatisfyingVersion(version, requires) { if (version == null || requires == null || _$1.isEmpty(requires)) { return []; } return filterNonNull(requires) .filter((v) => semver__namespace.satisfies(version, v)) .filter((v) => v != null); } /** * Returns the minimum satisfying version for the given version and required ranges. If there is * more than one range that is satisfied by the version, the minimum version is returned. * @param version - The version to check as a string or SemVer object. * @param ranges - The required versions as semver ranges or `null` to allow version without specifying a range. * @returns The minimum satisfying version. */ function getMinSatisfyingVersion(version, ranges) { const minVersions = getMinSatisfyingVersions(version, ranges); return _$1.first(minVersions); } /** * Returns all minimum satisfying versions for the given version and required ranges. * @param version - The version to check as a string or SemVer object. * @param ranges - The required versions as semver ranges or `null` to allow version without specifying a range. * @returns All minimum satisfying versions for the given ranges sorted in ascending order. */ function getMinSatisfyingVersions(version, ranges) { if (!version || !ranges || !_$1.isString(version) || !_$1.isArray(ranges)) { return []; } if (filterNonNull(ranges).length === 0) { return []; } if (_$1.isEmpty(ranges)) { const v = semver__namespace.coerce(version); return v ? [v] : []; } const minVersions = ranges.reduce((acc, range) => { if (range != null && _$1.isString(range)) { const coercedVersion = semver__namespace.coerce(version) ?? version; if (semver__namespace.satisfies(coercedVersion, range)) { const v = semver__namespace.minVersion(range); if (v) acc.push(v); } } else { const v = semver__namespace.coerce(version); if (v) acc.push(v); } return acc; }, []); return semver__namespace.sort(minVersions); } /** * Returns the minimized version string for the given version. Trailing `.0` patch versions or * `.0.0` minor versions and patch versions are omitted. If the version is a prerelease or build version, * the full version is returned. * @param version - The version to minimize as a string or SemVer object. * @returns The minimized version string. */ function getMinimizedVersionString(version) { const semVerObj = _$1.isString(version) ? semver__namespace.parse(version) : version; if (semVerObj == null) return undefined; const props = ["major", "minor", "patch", "prerelease", "build"]; if (!props.every((prop) => prop in semVerObj)) { return undefined; } if (semVerObj.patch === 0 && semVerObj.minor === 0 && !semVerObj.prerelease.length && !semVerObj.build.length) { return `${semVerObj.major}`; } else if (semVerObj.patch === 0 && !semVerObj.prerelease.length && !semVerObj.build.length) { return `${semVerObj.major}.${semVerObj.minor}`; } else { return semVerObj.version; } } /** * Converts the given version to a semver compatible version string. This is for * example converting `1.2` to `1.2.0`. * @param version - The version to convert. * @returns The semver version string. */ function toSemverVersion(version) { if (version == null) return undefined; // version could possibly be a number, make sure to always convert to string const result = semver__namespace.coerce(version.toString()); return result?.toString(); } function filterNonNull(items) { return items.filter((item) => item !== null); } function getAuthCookies(response) { let setCookie = response.headers.getSetCookie; let cookieHeader; if (typeof response.headers.getSetCookie === "function") { cookieHeader = response.headers.getSetCookie(); } else { if (typeof response.headers.get === "function") { setCookie = response.headers.get("set-cookie"); if (_$2.isString(setCookie)) { cookieHeader = setCookieParser__namespace.splitCookiesString(setCookie); } else if (_$2.isArrayLike(setCookie)) { cookieHeader = setCookie; } } else { if (_$2.isPlainObject(response.headers)) { cookieHeader = get_i(response.headers, "set-cookie"); } } } if (!cookieHeader) return undefined; let authorization = undefined; let xsrfToken = undefined; setCookieParser__namespace.parse(cookieHeader || []).forEach((c) => { if (_$2.isEqual(c.name.toLowerCase(), "authorization")) { authorization = c.value; } if (_$2.isEqual(c.name.toLowerCase(), "xsrf-token")) { xsrfToken = c.value; } }); // This method is intended for use on server environments (for example Node.js). // Browsers block frontend JavaScript code from accessing the Set-Cookie header, // as required by the Fetch spec, which defines Set-Cookie as a forbidden // response-header name that must be filtered out from any response exposed to frontend code. // https://developer.mozilla.org/en-US/docs/Web/API/Headers/getSetCookie if (!authorization) { authorization = getCookieValue("authorization") || getCookieValue("Authorization"); if (_$2.isEmpty(authorization)) { authorization = undefined; } } if (!xsrfToken) { xsrfToken = getCookieValue("XSRF-TOKEN") || getCookieValue("xsrf-token"); if (_$2.isEmpty(xsrfToken)) { xsrfToken = undefined; } } // remove quotes if xsrfToken value is wrapped in quotes, which can happen when the cookie value contains special characters like comma if (xsrfToken && xsrfToken.startsWith('"') && xsrfToken.endsWith('"')) { xsrfToken = xsrfToken.substring(1, xsrfToken.length - 1); } if (authorization && authorization.startsWith('"') && authorization.endsWith('"')) { authorization = authorization.substring(1, authorization.length - 1); } return { authorization, xsrfToken }; } // from c8y/client FetchClient function getCookieValue(name) { if (typeof document === "undefined") return undefined; const value = document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)"); return value ? value.pop() : ""; } async function oauthLogin(auth, baseUrl) { if (!auth || !auth.user || !auth.password) { const error = new Error("Authentication required. oauthLogin requires user and password for authentication."); error.name = "C8yPactError"; throw error; } if (!baseUrl) { const error = new Error("Base URL required. oauthLogin requires absolute url for login."); error.name = "C8yPactError"; throw error; } const tenant = auth.tenant; const tenant_id = tenant ? `?tenant_id=${tenant}` : ""; const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, baseUrl.lastIndexOf("/")) : baseUrl; const oauthEndpointUrl = `${normalizedBaseUrl}/tenant/oauth${tenant_id}`; const params = new URLSearchParams({ grant_type: "PASSWORD", username: auth.user || "", password: auth.password || "", ...(auth.tfa && { tfa_code: auth.tfa }), }); const oauthResponse = await fetch(oauthEndpointUrl, { method: "POST", body: params.toString(), headers: { "content-type": "application/x-www-form-urlencoded;charset=UTF-8", }, }); if (oauthResponse.status !== 200) { const error = new Error(`Logging in to ${baseUrl} failed for user "${auth.user}" with status code ${oauthResponse.status}.${oauthResponse.body ? "\n" + (await oauthResponse.text()) : ""}`); error.name = "C8yPactError"; throw error; } const cookies = getAuthCookies(oauthResponse); // Assuming getAuthCookies works with standard Response const { authorization, xsrfToken } = _$2.pick(cookies, [ "authorization", "xsrfToken", ]); auth = { ...auth, ...(authorization && { token: authorization }), ...(xsrfToken && { xsrfToken: xsrfToken }), }; return auth; } /// <reference types="cypress" /> // workaround for lodash import in Cypress nodejs typescript runtime and browser const _ = _$2 || ___namespace; /** * Checks if the given object is a C8yPactRecord. * * @param obj The object to check. * @returns True if the object is a C8yPactRecord, false otherwise. */ function isPactRecord(obj) { return (_.isObjectLike(obj) && "request" in obj && _.isObjectLike(_.get(obj, "request")) && "response" in obj && _.isObjectLike(_.get(obj, "response")) && _.isFunction(_.get(obj, "toCypressResponse"))); } /** * Converts the given object to a Cypress.Response. * @param obj The object to convert. * @param duration The duration of the request. * @param fetchOptions The fetch options used for the request. * @param url The URL of the request. * @param schema The schema of the response. */ function toCypressResponse(obj, duration = 0, fetchOptions = {}, url, schema) { if (!obj) return undefined; if (typeof isPactRecord === "function" && isPactRecord(obj)) { return obj.toCypressResponse(); } let fetchResponse; if (isIResult(obj)) { fetchResponse = obj.res; } else if (isWindowFetchResponse(obj)) { fetchResponse = obj; } else { fetchResponse = obj; } if ("responseObj" in fetchResponse) { return _$2.get(fetchResponse, "responseObj"); } return { status: fetchResponse.status, isOkStatusCode: fetchResponse.ok || (fetchResponse.status > 199 && fetchResponse.status < 300), statusText: fetchResponse.statusText, headers: Object.fromEntries(fetchResponse.headers || []), requestHeaders: fetchOptions.headers, duration: duration, ...(url && { url: toUrlString(url) }), allRequestResponses: [], body: fetchResponse.data, requestBody: fetchResponse.requestBody, method: fetchResponse.method || "GET", ...(schema && { $body: schema }), }; } /** * Checks if the given object is a window.Response. * @param obj The object to check. */ function isWindowFetchResponse(obj) { return (obj != null && _$2.isObjectLike(obj) && "status" in obj && "statusText" in obj && "headers" in obj && "body" in obj && "url" in obj && _$2.isFunction(_$2.get(obj, "json")) && _$2.isFunction(_$2.get(obj, "arrayBuffer"))); } /** * Checks if the given object is an IResult. * @param obj The object to check. */ function isIResult(obj) { return (obj != null && _$2.isObjectLike(obj) && "data" in obj && "res" in obj && isWindowFetchResponse(obj.res)); } /** * Checks if the given object is a CypressError. * @param error The object to check. * @returns True if the object is a CypressError, false otherwise. */ function isCypressError(error) { return _$2.isError(error) && _$2.get(error, "name") === "CypressError"; } exports.C8yPactAuthObjectKeys = C8yPactAuthObjectKeys; exports.authWithTenant = authWithTenant; exports.decodeBase64 = decodeBase64; exports.encodeBase64 = encodeBase64; exports.getAuthOptionsFromBasicAuthHeader = getAuthOptionsFromBasicAuthHeader; exports.getAuthOptionsFromEnv = getAuthOptionsFromEnv; exports.getAuthOptionsFromJWT = getAuthOptionsFromJWT; exports.getAuthType = getAuthType; exports.getMinSatisfyingVersion = getMinSatisfyingVersion; exports.getMinSatisfyingVersions = getMinSatisfyingVersions; exports.getMinimizedVersionString = getMinimizedVersionString; exports.getRangesSatisfyingVersion = getRangesSatisfyingVersion; exports.get_i = get_i; exports.hasAuthentication = hasAuthentication; exports.isAbsoluteURL = isAbsoluteURL; exports.isAuthOptions = isAuthOptions; exports.isCypressError = isCypressError; exports.isIResult = isIResult; exports.isPactAuthObject = isPactAuthObject; exports.isURL = isURL; exports.isVersionSatisfyingRequirements = isVersionSatisfyingRequirements; exports.isWindowFetchResponse = isWindowFetchResponse; exports.normalizeAuthHeaders = normalizeAuthHeaders; exports.normalizeBaseUrl = normalizeBaseUrl; exports.normalizeUrl = normalizeUrl; exports.oauthLogin = oauthLogin; exports.relativeURL = relativeURL; exports.removeBaseUrlFromString = removeBaseUrlFromString; exports.safeStringify = safeStringify; exports.sanitizeStringifiedObject = sanitizeStringifiedObject; exports.tenantFromBasicAuth = tenantFromBasicAuth; exports.tenantUrl = tenantUrl; exports.toC8yAuthentication = toC8yAuthentication; exports.toCypressResponse = toCypressResponse; exports.toPactAuthObject = toPactAuthObject; exports.toSemverVersion = toSemverVersion; exports.to_array = to_array; exports.to_boolean = to_boolean; //# sourceMappingURL=index.js.map