switch authenticated health checks to api keys
This commit is contained in:
parent
8f90385f3f
commit
1faa5c3319
|
@ -1,5 +1,5 @@
|
|||
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
|
||||
more_set_headers 'Access-Control-Allow-Credentials: true';
|
||||
more_set_headers 'Access-Control-Allow-Methods: GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE';
|
||||
more_set_headers 'Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,If-None-Match,Cache-Control,Content-Type,Range,X-HTTP-Method-Override,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,upload-concat,location,Skynet-API-Key';
|
||||
more_set_headers 'Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,If-Modified-Since,If-None-Match,Cache-Control,Content-Type,Range,X-HTTP-Method-Override,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,upload-concat,location,Skynet-Api-Key';
|
||||
more_set_headers 'Access-Control-Expose-Headers: Content-Length,Content-Range,ETag,Skynet-File-Metadata,Skynet-Skylink,Skynet-Proof,Skynet-Portal-Api,Skynet-Server-Api,upload-offset,upload-metadata,upload-length,tus-version,tus-resumable,tus-extension,tus-max-size,upload-concat,location';
|
||||
|
|
|
@ -6,16 +6,6 @@ require("yargs/yargs")(process.argv.slice(2))
|
|||
.help()
|
||||
.demandCommand()
|
||||
.strict(true)
|
||||
.command(
|
||||
"__authenticate", // Internal only function - this function will be removed when API keys are implemented
|
||||
false, // hide this function cli help
|
||||
() => {},
|
||||
async () => {
|
||||
const { getAuthCookie } = require("../src/utils");
|
||||
|
||||
console.log(await getAuthCookie(true));
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"enable",
|
||||
"Mark portal as enabled",
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
const got = require("got");
|
||||
const FormData = require("form-data");
|
||||
const { isEqual } = require("lodash");
|
||||
const { calculateElapsedTime, getResponseContent, getAuthCookie, isPortalModuleEnabled } = require("../utils");
|
||||
const { calculateElapsedTime, getResponseContent, isPortalModuleEnabled } = require("../utils");
|
||||
const { SkynetClient, stringToUint8ArrayUtf8, genKeyPairAndSeed } = require("skynet-js");
|
||||
|
||||
const MODULE_BLOCKER = "b";
|
||||
|
||||
const skynetClient = new SkynetClient(process.env.SKYNET_PORTAL_API);
|
||||
const skynetClient = new SkynetClient(process.env.SKYNET_PORTAL_API, {
|
||||
skynetApiKey: process.env.ACCOUNTS_TEST_USER_API_KEY,
|
||||
});
|
||||
const exampleSkylink = "AACogzrAimYPG42tDOKhS3lXZD8YvlF8Q8R17afe95iV2Q";
|
||||
|
||||
// check that any relevant configuration is properly set in skyd
|
||||
|
@ -36,7 +38,6 @@ async function skydConfigCheck(done) {
|
|||
|
||||
// uploadCheck returns the result of uploading a sample file
|
||||
async function uploadCheck(done) {
|
||||
const authCookie = await getAuthCookie();
|
||||
const time = process.hrtime();
|
||||
const form = new FormData();
|
||||
const payload = Buffer.from(new Date()); // current date to ensure data uniqueness
|
||||
|
@ -47,7 +48,9 @@ async function uploadCheck(done) {
|
|||
try {
|
||||
const response = await got.post(`${process.env.SKYNET_PORTAL_API}/skynet/skyfile`, {
|
||||
body: form,
|
||||
headers: { cookie: authCookie },
|
||||
headers: {
|
||||
"Skynet-Api-Key": process.env.ACCOUNTS_TEST_USER_API_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
|
@ -106,15 +109,14 @@ async function accountWebsiteCheck(done) {
|
|||
|
||||
// registryWriteAndReadCheck writes to registry and immediately reads and compares the data
|
||||
async function registryWriteAndReadCheck(done) {
|
||||
const authCookie = await getAuthCookie();
|
||||
const time = process.hrtime();
|
||||
const data = { name: "registry_write_and_read", up: false };
|
||||
const { privateKey, publicKey } = genKeyPairAndSeed();
|
||||
const expected = { dataKey: "foo-key", data: stringToUint8ArrayUtf8("foo-data"), revision: BigInt(0) };
|
||||
|
||||
try {
|
||||
await skynetClient.registry.setEntry(privateKey, expected, { customCookie: authCookie });
|
||||
const { entry } = await skynetClient.registry.getEntry(publicKey, expected.dataKey, { customCookie: authCookie });
|
||||
await skynetClient.registry.setEntry(privateKey, expected);
|
||||
const { entry } = await skynetClient.registry.getEntry(publicKey, expected.dataKey);
|
||||
|
||||
if (isEqual(expected, entry)) {
|
||||
data.up = true;
|
||||
|
@ -204,12 +206,16 @@ async function blockerHealthCheck(done) {
|
|||
}
|
||||
|
||||
async function genericAccessCheck(name, url) {
|
||||
const authCookie = await getAuthCookie();
|
||||
const time = process.hrtime();
|
||||
const data = { up: false, url };
|
||||
|
||||
try {
|
||||
const response = await got(url, { headers: { cookie: `nocache=true;${authCookie}` } });
|
||||
const response = await got(url, {
|
||||
headers: {
|
||||
cookie: "nocache=true",
|
||||
"Skynet-Api-Key": process.env.ACCOUNTS_TEST_USER_API_KEY,
|
||||
},
|
||||
});
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
data.up = true;
|
||||
|
|
|
@ -2,7 +2,7 @@ const got = require("got");
|
|||
const hasha = require("hasha");
|
||||
const { detailedDiff } = require("deep-object-diff");
|
||||
const { isEqual } = require("lodash");
|
||||
const { calculateElapsedTime, ensureValidJSON, getResponseContent, getAuthCookie } = require("../utils");
|
||||
const { calculateElapsedTime, ensureValidJSON, getResponseContent } = require("../utils");
|
||||
const { parseSkylink } = require("skynet-js");
|
||||
|
||||
// audioExampleCheck returns the result of trying to download the skylink
|
||||
|
@ -1130,13 +1130,18 @@ function parseHeaderString(header) {
|
|||
|
||||
// skylinkVerification verifies a skylink against provided information.
|
||||
async function skylinkVerification(done, expected, { followRedirect = true, method = "get" } = {}) {
|
||||
const authCookie = await getAuthCookie();
|
||||
const time = process.hrtime();
|
||||
const details = { name: expected.name, skylink: expected.skylink };
|
||||
|
||||
try {
|
||||
const query = `${process.env.SKYNET_PORTAL_API}/${expected.skylink}`;
|
||||
const response = await got[method](query, { followRedirect, headers: { cookie: `nocache=true;${authCookie}` } });
|
||||
const response = await got[method](query, {
|
||||
followRedirect,
|
||||
headers: {
|
||||
cookie: "nocache=true",
|
||||
"Skynet-Api-Key": process.env.ACCOUNTS_TEST_USER_API_KEY,
|
||||
},
|
||||
});
|
||||
const entry = { ...details, up: true, statusCode: response.statusCode, time: calculateElapsedTime(time) };
|
||||
const info = {};
|
||||
|
||||
|
|
|
@ -61,70 +61,6 @@ function getRequiredEnvironmentVariable(name) {
|
|||
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
|
||||
*/
|
||||
|
@ -137,7 +73,6 @@ module.exports = {
|
|||
getYesterdayISOString,
|
||||
getResponseContent,
|
||||
ensureValidJSON,
|
||||
getAuthCookie,
|
||||
isPortalModuleEnabled,
|
||||
ipCheckService,
|
||||
ipRegex,
|
||||
|
|
Reference in New Issue