Compare commits

...
This repository has been archived on 2022-10-07. You can view files and clone it, but cannot push or open issues or pull requests.

6 Commits

Author SHA1 Message Date
Karol Wypchło ce1d450edd
Merge branch 'master' into switch-authenticated-health-checks-to-api-key 2022-04-27 14:50:35 +02:00
Karol Wypchło 341814cd0a
Update cors-headers 2022-03-22 18:28:47 +01:00
Karol Wypchło f18272f1af
Merge branch 'master' into switch-authenticated-health-checks-to-api-key 2022-03-22 18:24:30 +01:00
Karol Wypchło 12906dffdb
Merge branch 'master' into switch-authenticated-health-checks-to-api-key 2022-02-18 10:52:57 +01:00
Karol Wypchlo 5abe647c2b
update skynet-js to include skynetApiKey 2022-02-17 12:22:45 +01:00
Karol Wypchlo 1faa5c3319
switch authenticated health checks to api keys 2022-02-16 12:30:54 +01:00
5 changed files with 25 additions and 88 deletions

View File

@ -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,Accept-Ranges,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';

View File

@ -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",

View File

@ -1,12 +1,15 @@
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(`https://${process.env.PORTAL_DOMAIN}`);
const skynetClient = new SkynetClient(`https://${process.env.PORTAL_DOMAIN}`, {
skynetApiKey: process.env.ACCOUNTS_TEST_USER_API_KEY,
});
const exampleSkylink = "AACogzrAimYPG42tDOKhS3lXZD8YvlF8Q8R17afe95iV2Q";
// check that any relevant configuration is properly set in skyd
@ -36,7 +39,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 +49,9 @@ async function uploadCheck(done) {
try {
const response = await got.post(`https://${process.env.PORTAL_DOMAIN}/skynet/skyfile`, {
body: form,
headers: { cookie: authCookie },
headers: {
"Skynet-Api-Key": process.env.ACCOUNTS_TEST_USER_API_KEY,
},
});
data.statusCode = response.statusCode;
@ -98,15 +102,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;
@ -196,12 +199,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;

View File

@ -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 = `https://${process.env.PORTAL_DOMAIN}/${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 = {};

View File

@ -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,