cumulocity-cypress
Version:
Cypress commands for Cumulocity IoT
1,010 lines (997 loc) • 37 kB
JavaScript
;
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