support auth only portal mode in health-check module

This commit is contained in:
Karol Wypchlo 2022-01-13 21:41:56 +01:00
parent e01b76217c
commit 5065e66b46
No known key found for this signature in database
GPG Key ID: B515DE9EEBE241E1
4 changed files with 76 additions and 7 deletions

View File

@ -1,7 +1,7 @@
const got = require("got"); const got = require("got");
const FormData = require("form-data"); const FormData = require("form-data");
const { isEqual } = require("lodash"); const { isEqual } = require("lodash");
const { calculateElapsedTime, getResponseContent } = require("../utils"); const { calculateElapsedTime, getResponseContent, getAuthCookie } = require("../utils");
const { SkynetClient, stringToUint8ArrayUtf8, genKeyPairAndSeed } = require("skynet-js"); const { SkynetClient, stringToUint8ArrayUtf8, genKeyPairAndSeed } = require("skynet-js");
const skynetClient = new SkynetClient(process.env.SKYNET_PORTAL_API); const skynetClient = new SkynetClient(process.env.SKYNET_PORTAL_API);
@ -34,6 +34,7 @@ async function skydConfigCheck(done) {
// uploadCheck returns the result of uploading a sample file // uploadCheck returns the result of uploading a sample file
async function uploadCheck(done) { async function uploadCheck(done) {
const authCookie = await getAuthCookie();
const time = process.hrtime(); const time = process.hrtime();
const form = new FormData(); const form = new FormData();
const payload = Buffer.from(new Date()); // current date to ensure data uniqueness const payload = Buffer.from(new Date()); // current date to ensure data uniqueness
@ -42,7 +43,10 @@ async function uploadCheck(done) {
form.append("file", payload, { filename: "time.txt", contentType: "text/plain" }); form.append("file", payload, { filename: "time.txt", contentType: "text/plain" });
try { try {
const response = await got.post(`${process.env.SKYNET_PORTAL_API}/skynet/skyfile`, { body: form }); const response = await got.post(`${process.env.SKYNET_PORTAL_API}/skynet/skyfile`, {
body: form,
headers: { cookie: authCookie },
});
data.statusCode = response.statusCode; data.statusCode = response.statusCode;
data.up = true; data.up = true;
@ -170,11 +174,12 @@ async function accountHealthCheck(done) {
} }
async function genericAccessCheck(name, url) { async function genericAccessCheck(name, url) {
const authCookie = await getAuthCookie();
const time = process.hrtime(); const time = process.hrtime();
const data = { up: false, url }; const data = { up: false, url };
try { try {
const response = await got(url, { headers: { cookie: "nocache=true" } }); const response = await got(url, { headers: { cookie: `nocache=true;${authCookie}` } });
data.statusCode = response.statusCode; data.statusCode = response.statusCode;
data.up = true; data.up = true;

View File

@ -2,7 +2,7 @@ const got = require("got");
const hasha = require("hasha"); const hasha = require("hasha");
const { detailedDiff } = require("deep-object-diff"); const { detailedDiff } = require("deep-object-diff");
const { isEqual } = require("lodash"); const { isEqual } = require("lodash");
const { calculateElapsedTime, ensureValidJSON, getResponseContent } = require("../utils"); const { calculateElapsedTime, ensureValidJSON, getResponseContent, getAuthCookie } = require("../utils");
const { parseSkylink } = require("skynet-js"); const { parseSkylink } = require("skynet-js");
// audioExampleCheck returns the result of trying to download the skylink // audioExampleCheck returns the result of trying to download the skylink
@ -1130,12 +1130,13 @@ function parseHeaderString(header) {
// skylinkVerification verifies a skylink against provided information. // skylinkVerification verifies a skylink against provided information.
async function skylinkVerification(done, expected, { followRedirect = true, method = "get" } = {}) { async function skylinkVerification(done, expected, { followRedirect = true, method = "get" } = {}) {
const authCookie = await getAuthCookie();
const time = process.hrtime(); const time = process.hrtime();
const details = { name: expected.name, skylink: expected.skylink }; const details = { name: expected.name, skylink: expected.skylink };
try { try {
const query = `${process.env.SKYNET_PORTAL_API}/${expected.skylink}`; const query = `${process.env.SKYNET_PORTAL_API}/${expected.skylink}`;
const response = await got[method](query, { followRedirect, headers: { cookie: "nocache=true" } }); const response = await got[method](query, { followRedirect, headers: { cookie: `nocache=true;${authCookie}` } });
const entry = { ...details, up: true, statusCode: response.statusCode, time: calculateElapsedTime(time) }; const entry = { ...details, up: true, statusCode: response.statusCode, time: calculateElapsedTime(time) };
const info = {}; const info = {};

View File

@ -4,8 +4,18 @@ if (!process.env.SKYNET_PORTAL_API) {
throw new Error("You need to provide SKYNET_PORTAL_API environment variable"); throw new Error("You need to provide SKYNET_PORTAL_API environment variable");
} }
if (process.env.ACCOUNTS_ENABLED === "true" && !process.env.SKYNET_DASHBOARD_URL) { if (process.env.ACCOUNTS_ENABLED === "true") {
if (!process.env.SKYNET_DASHBOARD_URL) {
throw new Error("You need to provide SKYNET_DASHBOARD_URL environment variable when accounts are enabled"); throw new Error("You need to provide SKYNET_DASHBOARD_URL environment variable when accounts are enabled");
}
if (process.env.ACCOUNTS_LIMIT_ACCESS === "authenticated") {
if (!process.env.ACCOUNTS_TEST_USER_EMAIL) {
throw new Error("ACCOUNTS_TEST_USER_EMAIL cannot be empty");
}
if (!process.env.ACCOUNTS_TEST_USER_PASSWORD) {
throw new Error("ACCOUNTS_TEST_USER_PASSWORD cannot be empty");
}
}
} }
const express = require("express"); const express = require("express");

View File

@ -1,3 +1,5 @@
const got = require("got");
/** /**
* Get the time between start and now in milliseconds * Get the time between start and now in milliseconds
*/ */
@ -39,9 +41,60 @@ function ensureValidJSON(object) {
return JSON.parse(stringified); return JSON.parse(stringified);
} }
/**
* 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
*/
function getAuthCookie() {
// cache auth promise so only one actual request will be made
if (getAuthCookie.cache) return getAuthCookie.cache;
// do not authenticate if it is not necessary
if (process.env.ACCOUNTS_LIMIT_ACCESS !== "authenticated") return {};
const email = process.env.ACCOUNTS_TEST_USER_EMAIL;
const password = process.env.ACCOUNTS_TEST_USER_PASSWORD;
if (!email) throw new Error("ACCOUNTS_TEST_USER_EMAIL cannot be empty");
if (!password) throw new Error("ACCOUNTS_TEST_USER_PASSWORD cannot be empty");
async function authenticate() {
try {
// authenticate with given test credentials
const response = await got.post(`${process.env.SKYNET_DASHBOARD_URL}/api/login`, {
json: { email, password },
});
// extract set-cookie from successful authentication request
const cookies = response.headers["set-cookie"];
// find the skynet-jwt cookie
const jwtcookie = cookies.find((cookie) => cookie.startsWith("skynet-jwt"));
// 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(`${process.env.SKYNET_DASHBOARD_URL}/api/user`, {
json: { email, password },
});
// retry authentication
return authenticate();
}
}
}
return (getAuthCookie.cache = authenticate());
}
module.exports = { module.exports = {
calculateElapsedTime, calculateElapsedTime,
getYesterdayISOString, getYesterdayISOString,
getResponseContent, getResponseContent,
ensureValidJSON, ensureValidJSON,
getAuthCookie,
}; };