const ipCheckService = "whatismyip.akamai.com"; const ipRegex = new RegExp( `^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:\\.(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$` ); /** * Get the time between start and now in milliseconds */ function calculateElapsedTime(start) { const diff = process.hrtime(start); return Math.round((diff[0] * 1e9 + diff[1]) / 1e6); // msec } /** * Get the ISO string with yesterday's date set (- 24 hours) */ function getYesterdayISOString() { const date = new Date(); date.setDate(date.getDate() - 1); return date.toISOString(); } /** * Get response from response object if available */ function getResponseContent(response) { try { return JSON.parse(response?.body || response?.text); } catch { return response?.body || response?.text; } } /** * Ensures that the object serializes to JSON properly */ function ensureValidJSON(object) { const replacer = (key, value) => (value === undefined ? "--undefined--" : value); const stringified = JSON.stringify(object, replacer); return JSON.parse(stringified); } /** * Get variable value from environment (process.env) * Exit with code 1 if variable is not set or empty * @param {string} name variable name * @returns {string} */ function getRequiredEnvironmentVariable(name) { const value = process.env[name]; if (!value) { console.log(`${name} cannot be empty`); process.exit(1); } return value; } /** * Authenticate with given credentials and return auth cookie * Creates new account if username does not exist * Only authenticates when portal is set to authenticated users only mode * @param {boolean} forceAuth forcibly ensure authentication with test credentials */ function getAuthCookie(forceAuth = false) { // cache auth promise so only one actual request will be made if (getAuthCookie.cache) return getAuthCookie.cache; // accounts disabled, do not try to authenticate if (!isPortalModuleEnabled("a")) return ""; // do not authenticate if it is not required by portal limit access rule if (!forceAuth && !["authenticated", "subscription"].includes(process.env.ACCOUNTS_LIMIT_ACCESS)) return ""; // assign all required environment variables const portalDomain = getRequiredEnvironmentVariable("PORTAL_DOMAIN"); const email = getRequiredEnvironmentVariable("ACCOUNTS_TEST_USER_EMAIL"); const password = getRequiredEnvironmentVariable("ACCOUNTS_TEST_USER_PASSWORD"); async function authenticate() { const got = require("got"); try { // authenticate with given test user credentials const response = await got.post(`https://account.${portalDomain}/api/login`, { json: { email, password }, }); // extract set-cookie from successful authentication request const cookies = response.headers["set-cookie"]; // throw meaningful error when set-cookie header is missing if (!cookies) throw new Error(`Auth successful (code ${response.statusCode}) but 'set-cookie' header is missing`); // find the skynet-jwt cookie const jwtcookie = cookies.find((cookie) => cookie.startsWith("skynet-jwt")); // throw meaningful error when skynet-jwt cookie is missing if (!jwtcookie) throw new Error(`Header 'set-cookie' found but 'skynet-jwt' cookie is missing`); // extract just the cookie value (no set-cookie props) from set-cookie return jwtcookie.match(/skynet-jwt=[^;]+;/)[0]; } catch (error) { // 401 means that service worked but user could not have been authenticated if (error.response && error.response.statusCode === 401) { // sign up with the given credentials await got.post(`https://account.${portalDomain}/api/user`, { json: { email, password }, }); // retry authentication return authenticate(); } // rethrow unhandled exception throw error; } } return (getAuthCookie.cache = authenticate()); } /** * isPortalModuleEnabled returns true if the given module is enabled */ function isPortalModuleEnabled(module) { return process.env.PORTAL_MODULES && process.env.PORTAL_MODULES.indexOf(module) !== -1; } module.exports = { calculateElapsedTime, getYesterdayISOString, getResponseContent, ensureValidJSON, getAuthCookie, isPortalModuleEnabled, ipCheckService, ipRegex, };