Remove Health-Check package
This commit is contained in:
parent
dab29fead5
commit
ba72d340ab
|
@ -20,7 +20,6 @@ jobs:
|
|||
- packages/dashboard-v2/Dockerfile
|
||||
- packages/dnslink-api/Dockerfile
|
||||
- packages/handshake-api/Dockerfile
|
||||
- packages/health-check/Dockerfile
|
||||
- packages/website/Dockerfile
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
name: Lint - packages/health-check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/health-check/**
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/health-check
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- run: yarn
|
||||
- run: yarn prettier --check .
|
|
@ -1,23 +0,0 @@
|
|||
name: Test - packages/health-check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- packages/health-check/**
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/health-check
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.x
|
||||
|
||||
- run: yarn
|
||||
- run: yarn jest
|
|
@ -171,9 +171,9 @@ services:
|
|||
health-check:
|
||||
# uncomment "build" and comment out "image" to build from sources
|
||||
# build:
|
||||
# context: https://github.com/SkynetLabs/skynet-webportal.git#master
|
||||
# dockerfile: ./packages/health-check/Dockerfile
|
||||
image: skynetlabs/health-check
|
||||
# context: https://github.com/SkynetLabs/webportal-health-check.git#master
|
||||
# dockerfile: Dockerfile
|
||||
image: skynetlabs/webportal-health-check:0.1.2
|
||||
container_name: health-check
|
||||
restart: unless-stopped
|
||||
logging: *default-logging
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
state/
|
|
@ -1 +0,0 @@
|
|||
/package.json
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"printWidth": 120
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
FROM node:16.14.2-alpine
|
||||
|
||||
RUN apk add --no-cache dnsmasq~=2
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
ENV PATH="/usr/app/bin:${PATH}"
|
||||
|
||||
# schedule critical checks to run every 5 minutes (any failures will disable server)
|
||||
# schedule extended checks to run on every hour (optional checks, report only)
|
||||
RUN echo '*/5 * * * * source /etc/environment ; /usr/app/bin/cli run critical >> /proc/1/fd/1' >> /etc/crontabs/root && \
|
||||
echo '0 * * * * source /etc/environment ; /usr/app/bin/cli run extended >> /proc/1/fd/1' >> /etc/crontabs/root
|
||||
|
||||
COPY packages/health-check/package.json \
|
||||
packages/health-check/yarn.lock \
|
||||
./
|
||||
|
||||
RUN yarn --frozen-lockfile
|
||||
|
||||
COPY packages/health-check/src src
|
||||
COPY packages/health-check/cli cli
|
||||
COPY packages/health-check/bin bin
|
||||
|
||||
EXPOSE 3100
|
||||
ENV NODE_ENV production
|
||||
|
||||
# 1. get public server ip and save it in /etc/environment (passed to cron tasks as env variable)
|
||||
# 2. start dnsmasq in the background with:
|
||||
# - alias PORTAL_DOMAIN with current server ip so it overrides potential load balancer request
|
||||
# - default docker nameserver 127.0.0.11 for any other request
|
||||
# 3. replace docker nameserver with dnsmasq nameserver in /etc/resolv.conf
|
||||
# 4. start crond in the background to schedule periodic health checks
|
||||
# 5. start the health-check api service
|
||||
CMD [ "sh", "-c", \
|
||||
"export serverip=$(node src/whatismyip.js) && \
|
||||
echo \"export serverip=${serverip}\" >> /etc/environment && \
|
||||
dnsmasq --no-resolv --log-facility=/var/log/dnsmasq.log --address=/$PORTAL_DOMAIN/$serverip --server=127.0.0.11 && \
|
||||
echo \"$(sed 's/127.0.0.11/127.0.0.1/' /etc/resolv.conf)\" > /etc/resolv.conf && \
|
||||
crond && \
|
||||
node src/index.js" \
|
||||
]
|
|
@ -1,94 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || "production";
|
||||
|
||||
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",
|
||||
() => {},
|
||||
() => {
|
||||
const db = require("../src/db");
|
||||
|
||||
db.set("disabled", false).write();
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"disable <reason>",
|
||||
"Mark portal as disabled (provide meaningful reason)",
|
||||
() => {},
|
||||
({ reason }) => {
|
||||
const db = require("../src/db");
|
||||
|
||||
db.set("disabled", reason).write();
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"run <type>",
|
||||
"Skynet portal health checks",
|
||||
(yargs) => {
|
||||
yargs
|
||||
.positional("type", {
|
||||
describe: "Type of checks to run",
|
||||
type: "string",
|
||||
choices: ["critical", "extended"],
|
||||
})
|
||||
.option("portal-url", {
|
||||
describe: "Skynet portal url",
|
||||
default: process.env.PORTAL_DOMAIN ? `https://${process.env.PORTAL_DOMAIN}` : "https://siasky.net",
|
||||
type: "string",
|
||||
})
|
||||
.option("state-dir", {
|
||||
describe: "State directory",
|
||||
default: process.env.STATE_DIR || "state",
|
||||
type: "string",
|
||||
});
|
||||
},
|
||||
async ({ type, portalUrl, stateDir }) => {
|
||||
const { hostname: portalDomain } = new URL(portalUrl); // extract domain from portal url
|
||||
process.env.PORTAL_DOMAIN = portalDomain;
|
||||
process.env.STATE_DIR = stateDir;
|
||||
|
||||
const util = require("util");
|
||||
const { getYesterdayISOString } = require("../src/utils");
|
||||
const createMiddleware = require("../src/checks/middleware");
|
||||
const db = require("../src/db");
|
||||
const checks = require(`../src/checks/${type}`);
|
||||
const middleware = await createMiddleware();
|
||||
|
||||
const entry = {
|
||||
date: new Date().toISOString(),
|
||||
checks: (await Promise.all(checks.map((check) => new Promise(check)))).filter(Boolean).map(middleware),
|
||||
};
|
||||
|
||||
db.read() // read before writing to make sure no external changes are overwritten
|
||||
.get(type) // get the list of records of given type
|
||||
.push(entry) // insert new record
|
||||
.remove(({ date }) => date < getYesterdayISOString()) // drop old records
|
||||
.write();
|
||||
|
||||
// exit with code 1 if any of the checks report failure
|
||||
if (entry.checks.some(({ up }) => !up)) {
|
||||
console.log(
|
||||
util.inspect(
|
||||
entry.checks.filter(({ up }) => !up),
|
||||
{ colors: true, depth: 7 } // increase depth to ensure errors are printed
|
||||
)
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
).argv;
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/ash
|
||||
|
||||
echo "DEPRECATED: 'cli/disable' command is deprecated, use 'cli disable' instead"
|
||||
|
||||
/usr/app/bin/cli disable $@
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/ash
|
||||
|
||||
echo "DEPRECATED: 'cli/enable' command is deprecated, use 'cli enable' instead"
|
||||
|
||||
/usr/app/bin/cli enable $@
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/ash
|
||||
|
||||
echo "DEPRECATED: 'cli/run' command is deprecated, use 'cli run' instead"
|
||||
|
||||
/usr/app/bin/cli run $@
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"name": "health-check",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"deep-object-diff": "^1.1.7",
|
||||
"express": "^4.18.1",
|
||||
"form-data": "^4.0.0",
|
||||
"got": "^11.8.2",
|
||||
"graceful-fs": "^4.2.10",
|
||||
"hasha": "^5.2.2",
|
||||
"http-status-codes": "^2.2.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lowdb": "^1.0.0",
|
||||
"skynet-js": "^4.1.0",
|
||||
"write-file-atomic": "^4.0.1",
|
||||
"yargs": "^17.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^28.0.3",
|
||||
"prettier": "^2.6.2"
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
const fs = require("graceful-fs");
|
||||
const Base = require("lowdb/adapters/Base");
|
||||
const { sync: writeFileAtomicSync } = require("write-file-atomic");
|
||||
|
||||
class FileSyncAtomic extends Base {
|
||||
read() {
|
||||
if (fs.existsSync(this.source)) {
|
||||
try {
|
||||
const data = fs.readFileSync(this.source, "utf-8").trim();
|
||||
return data ? this.deserialize(data) : this.defaultValue;
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) {
|
||||
e.message = `Malformed JSON in file: ${this.source}\n${e.message}`;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
writeFileAtomicSync(this.source, this.serialize(this.defaultValue));
|
||||
return this.defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
write(data) {
|
||||
return writeFileAtomicSync(this.source, this.serialize(data));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FileSyncAtomic;
|
|
@ -1,14 +0,0 @@
|
|||
const db = require("../db");
|
||||
const { getYesterdayISOString } = require("../utils");
|
||||
|
||||
// returns all critical health check entries
|
||||
module.exports = (req, res) => {
|
||||
const yesterday = getYesterdayISOString();
|
||||
const entries = db
|
||||
.get("critical")
|
||||
.orderBy("date", "desc")
|
||||
.filter(({ date }) => date > yesterday)
|
||||
.value();
|
||||
|
||||
res.send(entries);
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
const db = require("../db");
|
||||
|
||||
// returns a disabled flag status
|
||||
module.exports = (req, res) => {
|
||||
const disabled = db.get("disabled").value();
|
||||
|
||||
res.send({ disabled });
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
const db = require("../db");
|
||||
const { getYesterdayISOString } = require("../utils");
|
||||
|
||||
// returns all extended health check entries
|
||||
module.exports = (req, res) => {
|
||||
const yesterday = getYesterdayISOString();
|
||||
const entries = db
|
||||
.get("extended")
|
||||
.orderBy("date", "desc")
|
||||
.filter(({ date }) => date > yesterday)
|
||||
.value();
|
||||
|
||||
res.send(entries);
|
||||
};
|
|
@ -1,75 +0,0 @@
|
|||
const { StatusCodes } = require("http-status-codes");
|
||||
const { sum, sumBy } = require("lodash");
|
||||
const db = require("../db");
|
||||
|
||||
/**
|
||||
* Get status code that should be returned in the API response.
|
||||
* - OK (200) in case everything is healthy
|
||||
* - SERVICE_UNAVAILABLE (503) in case of any failures or if disabled
|
||||
*/
|
||||
function getStatusCode() {
|
||||
// check whether the portal has been manually disabled
|
||||
const disabled = getDisabled();
|
||||
|
||||
if (disabled) {
|
||||
return StatusCodes.SERVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
// grab the most recent critical entry element from DB
|
||||
const entry = getMostRecentCriticalEntry();
|
||||
|
||||
// in case there is no entry yet or at least one check failed in the most recent entry
|
||||
if (!entry || entry.checks.some(({ up }) => !up)) {
|
||||
return StatusCodes.SERVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
return StatusCodes.OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sample of most recent critical entries and
|
||||
* calculate the average response time of all of them
|
||||
*/
|
||||
function getAverageResponseTime() {
|
||||
// get most recent 10 successfull checks for the calculation
|
||||
const sample = db
|
||||
.get("critical")
|
||||
.orderBy("date", "desc")
|
||||
.filter(({ checks }) => checks.every(({ up }) => up))
|
||||
.take(10)
|
||||
.value();
|
||||
|
||||
// calculate average time of response
|
||||
return Math.round(sum(sample.map(({ checks }) => sumBy(checks, "time"))) / sample.size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one, most current critical entry
|
||||
*/
|
||||
function getMostRecentCriticalEntry() {
|
||||
return db.get("critical").orderBy("date", "desc").head().value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the disabled flag state (manual portal disable)
|
||||
*/
|
||||
function getDisabled() {
|
||||
return db.get("disabled").value();
|
||||
}
|
||||
|
||||
module.exports = (req, res) => {
|
||||
const statusCode = getStatusCode();
|
||||
const timeout = statusCode === StatusCodes.OK ? getAverageResponseTime() : 0;
|
||||
|
||||
// We want to delay the response for the load balancer to be able to prioritize
|
||||
// servers based on the successful response time of this endpoint. Load balancer
|
||||
// will pull the server if the response is an error so there is no point in delaying
|
||||
// failures, hence 0 timeout on those.
|
||||
setTimeout(() => {
|
||||
// include some health information in the response body
|
||||
const entry = getMostRecentCriticalEntry();
|
||||
const disabled = getDisabled();
|
||||
|
||||
res.status(statusCode).send({ disabled, entry });
|
||||
}, timeout);
|
||||
};
|
|
@ -1,239 +0,0 @@
|
|||
const got = require("got");
|
||||
const FormData = require("form-data");
|
||||
const { isEqual } = require("lodash");
|
||||
const { calculateElapsedTime, getResponseContent, getAuthCookie, isPortalModuleEnabled } = require("../utils");
|
||||
const { SkynetClient, stringToUint8ArrayUtf8, genKeyPairAndSeed } = require("skynet-js");
|
||||
|
||||
const MODULE_BLOCKER = "b";
|
||||
|
||||
const skynetClient = new SkynetClient(`https://${process.env.PORTAL_DOMAIN}`);
|
||||
const exampleSkylink = "AACogzrAimYPG42tDOKhS3lXZD8YvlF8Q8R17afe95iV2Q";
|
||||
|
||||
// check that any relevant configuration is properly set in skyd
|
||||
async function skydConfigCheck(done) {
|
||||
const time = process.hrtime();
|
||||
const data = { up: false };
|
||||
|
||||
try {
|
||||
const response = await got(`http://10.10.10.10:9980/renter`, { headers: { "User-Agent": "Sia-Agent" } }).json();
|
||||
|
||||
// make sure initial funding is set to 10SC
|
||||
if (response.settings.allowance.paymentcontractinitialfunding !== "10000000000000000000000000") {
|
||||
throw new Error("Skynet Portal Per-Contract Budget is not set correctly!");
|
||||
}
|
||||
|
||||
data.up = true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
data.statusCode = error.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
done({ name: "skyd_config", time: calculateElapsedTime(time), ...data });
|
||||
}
|
||||
|
||||
// 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
|
||||
const data = { up: false };
|
||||
|
||||
form.append("file", payload, { filename: "time.txt", contentType: "text/plain" });
|
||||
|
||||
try {
|
||||
const response = await got.post(`https://${process.env.PORTAL_DOMAIN}/skynet/skyfile`, {
|
||||
body: form,
|
||||
headers: { cookie: authCookie },
|
||||
});
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
data.up = true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
data.statusCode = error.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
done({ name: "upload_file", time: calculateElapsedTime(time), ...data });
|
||||
}
|
||||
|
||||
// websiteCheck checks whether the main website is working
|
||||
async function websiteCheck(done) {
|
||||
return done(await genericAccessCheck("website", `https://${process.env.PORTAL_DOMAIN}`));
|
||||
}
|
||||
|
||||
// downloadCheck returns the result of downloading the hard coded link
|
||||
async function downloadCheck(done) {
|
||||
const url = await skynetClient.getSkylinkUrl(exampleSkylink);
|
||||
|
||||
return done(await genericAccessCheck("skylink", url));
|
||||
}
|
||||
|
||||
// skylinkSubdomainCheck returns the result of downloading the hard coded link via subdomain
|
||||
async function skylinkSubdomainCheck(done) {
|
||||
const url = await skynetClient.getSkylinkUrl(exampleSkylink, { subdomain: true });
|
||||
|
||||
return done(await genericAccessCheck("skylink_via_subdomain", url));
|
||||
}
|
||||
|
||||
// handshakeSubdomainCheck returns the result of downloading the skylink via handshake domain
|
||||
async function handshakeSubdomainCheck(done) {
|
||||
const url = await skynetClient.getHnsUrl("note-to-self", { subdomain: true });
|
||||
|
||||
return done(await genericAccessCheck("hns_via_subdomain", url));
|
||||
}
|
||||
|
||||
// accountWebsiteCheck returns the result of accessing account dashboard website
|
||||
async function accountWebsiteCheck(done) {
|
||||
const url = `https://account.${process.env.PORTAL_DOMAIN}/auth/login`;
|
||||
|
||||
return done(await genericAccessCheck("account_website", url));
|
||||
}
|
||||
|
||||
// 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 });
|
||||
|
||||
if (isEqual(expected, entry)) {
|
||||
data.up = true;
|
||||
} else {
|
||||
data.errors = [{ message: "Data mismatch in registry (read after write)", entry, expected }];
|
||||
}
|
||||
} catch (error) {
|
||||
data.errors = [{ message: error?.response?.data?.message ?? error.message }];
|
||||
}
|
||||
|
||||
return done({ ...data, time: calculateElapsedTime(time) });
|
||||
}
|
||||
|
||||
// directServerApiAccessCheck returns the basic server api check on direct server address
|
||||
async function directServerApiAccessCheck(done) {
|
||||
// skip if SERVER_DOMAIN is not set or it equals PORTAL_DOMAIN (single server portals)
|
||||
if (!process.env.SERVER_DOMAIN || process.env.SERVER_DOMAIN === process.env.PORTAL_DOMAIN) {
|
||||
return done();
|
||||
}
|
||||
|
||||
const [portalAccessCheck, serverAccessCheck] = await Promise.all([
|
||||
genericAccessCheck("portal_api_access", `https://${process.env.PORTAL_DOMAIN}`),
|
||||
genericAccessCheck("server_api_access", `https://${process.env.SERVER_DOMAIN}`),
|
||||
]);
|
||||
|
||||
if (portalAccessCheck.ip !== serverAccessCheck.ip) {
|
||||
serverAccessCheck.up = false;
|
||||
serverAccessCheck.errors = serverAccessCheck.errors ?? [];
|
||||
serverAccessCheck.errors.push({
|
||||
message: "Access ip mismatch between portal and server access",
|
||||
response: {
|
||||
portal: { name: process.env.PORTAL_DOMAIN, ip: portalAccessCheck.ip },
|
||||
server: { name: process.env.SERVER_DOMAIN, ip: serverAccessCheck.ip },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return done(serverAccessCheck);
|
||||
}
|
||||
|
||||
// accountHealthCheck returns the result of accounts service health checks
|
||||
async function accountHealthCheck(done) {
|
||||
const time = process.hrtime();
|
||||
const data = { up: false };
|
||||
|
||||
try {
|
||||
const response = await got(`https://account.${process.env.PORTAL_DOMAIN}/health`, { responseType: "json" });
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
data.response = response.body;
|
||||
data.up = response.body.dbAlive === true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
data.statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
done({ name: "accounts", time: calculateElapsedTime(time), ...data });
|
||||
}
|
||||
|
||||
// blockerHealthCheck returns the result of blocker container health endpoint
|
||||
async function blockerHealthCheck(done) {
|
||||
const time = process.hrtime();
|
||||
const data = { up: false };
|
||||
|
||||
try {
|
||||
const response = await got(`http://${process.env.BLOCKER_HOST}:${process.env.BLOCKER_PORT}/health`, {
|
||||
responseType: "json",
|
||||
});
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
data.response = response.body;
|
||||
data.up = response.body.dbAlive === true;
|
||||
} catch (error) {
|
||||
data.statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
}
|
||||
|
||||
// this is a no-op but it's added to explicitly document the ip property
|
||||
// should not be set on the data object to prevent the IP from being compared
|
||||
// to the server's IP - this is not required for this check and will fail
|
||||
delete data.ip;
|
||||
|
||||
done({ name: "blocker", time: calculateElapsedTime(time), ...data });
|
||||
}
|
||||
|
||||
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}` } });
|
||||
|
||||
data.statusCode = response.statusCode;
|
||||
data.up = true;
|
||||
data.ip = response.ip;
|
||||
} catch (error) {
|
||||
data.statusCode = error?.response?.statusCode || error.statusCode || error.status;
|
||||
data.errorMessage = error.message;
|
||||
data.errorResponseContent = getResponseContent(error.response);
|
||||
data.ip = error?.response?.ip ?? null;
|
||||
}
|
||||
|
||||
return { name, time: calculateElapsedTime(time), ...data };
|
||||
}
|
||||
|
||||
const checks = [
|
||||
skydConfigCheck,
|
||||
uploadCheck,
|
||||
websiteCheck,
|
||||
downloadCheck,
|
||||
skylinkSubdomainCheck,
|
||||
handshakeSubdomainCheck,
|
||||
registryWriteAndReadCheck,
|
||||
directServerApiAccessCheck,
|
||||
];
|
||||
|
||||
if (process.env.ACCOUNTS_ENABLED === "true") {
|
||||
checks.push(accountHealthCheck, accountWebsiteCheck);
|
||||
}
|
||||
|
||||
if (isPortalModuleEnabled(MODULE_BLOCKER)) {
|
||||
checks.push(blockerHealthCheck);
|
||||
}
|
||||
|
||||
module.exports = checks;
|
File diff suppressed because it is too large
Load Diff
|
@ -1,45 +0,0 @@
|
|||
const got = require("got");
|
||||
const { ipCheckService, ipRegex } = require("../utils");
|
||||
|
||||
const getCurrentAddress = async () => {
|
||||
// use serverip env variable when available (set via Dockerfile)
|
||||
if (process.env.serverip) {
|
||||
if (ipRegex.test(process.env.serverip)) return process.env.serverip;
|
||||
|
||||
// log error to console for future reference but do not break
|
||||
console.log(`Environment variable serverip contains invalid ip: "${process.env.serverip}"`);
|
||||
}
|
||||
|
||||
try {
|
||||
const { body } = await got(`http://${ipCheckService}`);
|
||||
if (ipRegex.test(body)) {
|
||||
console.info(`Server public ip: ${body} (source: ${ipCheckService})`);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
throw new Error(`${ipCheckService} responded with invalid ip: "${body}"`);
|
||||
} catch (error) {
|
||||
console.log(error.message); // log error to console for future reference
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = async function middleware() {
|
||||
const ip = await getCurrentAddress();
|
||||
|
||||
return (check) => {
|
||||
// check only if current ip and check ip are provided
|
||||
if (ip && check.ip && check.ip !== ip) {
|
||||
check.up = false;
|
||||
check.errors = check.errors ?? [];
|
||||
check.errors.push({
|
||||
message: "Response ip was different than current server ip - possibly there was an error with routing request",
|
||||
data: { response: check.ip, server: ip },
|
||||
});
|
||||
}
|
||||
|
||||
return check;
|
||||
};
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
const fs = require("graceful-fs");
|
||||
const low = require("lowdb");
|
||||
const FileSyncAtomic = require("./adapters/FileSyncAtomic");
|
||||
|
||||
if (!fs.existsSync(process.env.STATE_DIR)) fs.mkdirSync(process.env.STATE_DIR);
|
||||
|
||||
const adapter = new FileSyncAtomic(`${process.env.STATE_DIR}/state.json`);
|
||||
const db = low(adapter);
|
||||
|
||||
db.defaults({ disabled: false, critical: [], extended: [] }).write();
|
||||
|
||||
module.exports = db;
|
|
@ -1,322 +0,0 @@
|
|||
{
|
||||
"filename": "output",
|
||||
"subfiles": {
|
||||
".well-known/brave-rewards-verification.txt": {
|
||||
"filename": ".well-known/brave-rewards-verification.txt",
|
||||
"contenttype": "text/plain",
|
||||
"len": 154
|
||||
},
|
||||
"404.html": { "filename": "404.html", "contenttype": "text/html", "offset": 154, "len": 5482 },
|
||||
"assets/bootstrap/bootstrap-grid.css": {
|
||||
"filename": "assets/bootstrap/bootstrap-grid.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 5636,
|
||||
"len": 49901
|
||||
},
|
||||
"assets/bootstrap/bootstrap-reboot.css": {
|
||||
"filename": "assets/bootstrap/bootstrap-reboot.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 55537,
|
||||
"len": 4187
|
||||
},
|
||||
"assets/bootstrap/bootstrap.css": {
|
||||
"filename": "assets/bootstrap/bootstrap.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 59724,
|
||||
"len": 172594
|
||||
},
|
||||
"assets/css/styles.css": {
|
||||
"filename": "assets/css/styles.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 232318,
|
||||
"len": 4887
|
||||
},
|
||||
"assets/fonts/dm-serif-display-v4-latin-regular.woff": {
|
||||
"filename": "assets/fonts/dm-serif-display-v4-latin-regular.woff",
|
||||
"contenttype": "application/font-woff",
|
||||
"offset": 237205,
|
||||
"len": 29916
|
||||
},
|
||||
"assets/fonts/dm-serif-display-v4-latin-regular.woff2": {
|
||||
"filename": "assets/fonts/dm-serif-display-v4-latin-regular.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 267121,
|
||||
"len": 24980
|
||||
},
|
||||
"assets/fonts/open-sans-v16-latin-regular.woff": {
|
||||
"filename": "assets/fonts/open-sans-v16-latin-regular.woff",
|
||||
"contenttype": "application/font-woff",
|
||||
"offset": 292101,
|
||||
"len": 18100
|
||||
},
|
||||
"assets/fonts/open-sans-v16-latin-regular.woff2": {
|
||||
"filename": "assets/fonts/open-sans-v16-latin-regular.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 310201,
|
||||
"len": 14380
|
||||
},
|
||||
"assets/fonts/questrial-v9-latin-regular.woff": {
|
||||
"filename": "assets/fonts/questrial-v9-latin-regular.woff",
|
||||
"contenttype": "application/font-woff",
|
||||
"offset": 324581,
|
||||
"len": 23048
|
||||
},
|
||||
"assets/fonts/questrial-v9-latin-regular.woff2": {
|
||||
"filename": "assets/fonts/questrial-v9-latin-regular.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 347629,
|
||||
"len": 13776
|
||||
},
|
||||
"assets/images/blog/2a40df99-1847-4726-9c5b-af4779eeb667-w1920-h1440.jpg": {
|
||||
"filename": "assets/images/blog/2a40df99-1847-4726-9c5b-af4779eeb667-w1920-h1440.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 361405,
|
||||
"len": 79551
|
||||
},
|
||||
"assets/images/blog/2a40df99-1847-4726-9c5b-af4779eeb667-w960-h720.jpg": {
|
||||
"filename": "assets/images/blog/2a40df99-1847-4726-9c5b-af4779eeb667-w960-h720.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 440956,
|
||||
"len": 31700
|
||||
},
|
||||
"assets/images/blog/2a40df99-1847-4726-9c5b-af4779eeb667.jpg": {
|
||||
"filename": "assets/images/blog/2a40df99-1847-4726-9c5b-af4779eeb667.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 472656,
|
||||
"len": 69094
|
||||
},
|
||||
"assets/images/blog/512e4dd1-6b3d-41aa-80a1-b96c3370b3c3-w1920-h1440.jpg": {
|
||||
"filename": "assets/images/blog/512e4dd1-6b3d-41aa-80a1-b96c3370b3c3-w1920-h1440.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 541750,
|
||||
"len": 219602
|
||||
},
|
||||
"assets/images/blog/512e4dd1-6b3d-41aa-80a1-b96c3370b3c3-w960-h720.jpg": {
|
||||
"filename": "assets/images/blog/512e4dd1-6b3d-41aa-80a1-b96c3370b3c3-w960-h720.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 761352,
|
||||
"len": 67741
|
||||
},
|
||||
"assets/images/blog/512e4dd1-6b3d-41aa-80a1-b96c3370b3c3.jpg": {
|
||||
"filename": "assets/images/blog/512e4dd1-6b3d-41aa-80a1-b96c3370b3c3.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 829093,
|
||||
"len": 226910
|
||||
},
|
||||
"assets/images/blog/823a7764-af7c-4687-a42e-bd70768068ab-w1920-h1440.jpg": {
|
||||
"filename": "assets/images/blog/823a7764-af7c-4687-a42e-bd70768068ab-w1920-h1440.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 1056003,
|
||||
"len": 258292
|
||||
},
|
||||
"assets/images/blog/823a7764-af7c-4687-a42e-bd70768068ab-w960-h720.jpg": {
|
||||
"filename": "assets/images/blog/823a7764-af7c-4687-a42e-bd70768068ab-w960-h720.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 1314295,
|
||||
"len": 93250
|
||||
},
|
||||
"assets/images/blog/823a7764-af7c-4687-a42e-bd70768068ab.jpg": {
|
||||
"filename": "assets/images/blog/823a7764-af7c-4687-a42e-bd70768068ab.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 1407545,
|
||||
"len": 236722
|
||||
},
|
||||
"assets/images/blog/9aeea0d6-737c-4be8-8b63-5ec38cbf394b-w1920-h1440.jpg": {
|
||||
"filename": "assets/images/blog/9aeea0d6-737c-4be8-8b63-5ec38cbf394b-w1920-h1440.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 1644267,
|
||||
"len": 285727
|
||||
},
|
||||
"assets/images/blog/9aeea0d6-737c-4be8-8b63-5ec38cbf394b-w960-h720.jpg": {
|
||||
"filename": "assets/images/blog/9aeea0d6-737c-4be8-8b63-5ec38cbf394b-w960-h720.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 1929994,
|
||||
"len": 115524
|
||||
},
|
||||
"assets/images/blog/9aeea0d6-737c-4be8-8b63-5ec38cbf394b.jpg": {
|
||||
"filename": "assets/images/blog/9aeea0d6-737c-4be8-8b63-5ec38cbf394b.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2045518,
|
||||
"len": 338905
|
||||
},
|
||||
"assets/images/blog/a1ee6dcf-55ef-43cd-ae05-682d2e28e932-w1920-h1440.jpg": {
|
||||
"filename": "assets/images/blog/a1ee6dcf-55ef-43cd-ae05-682d2e28e932-w1920-h1440.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2384423,
|
||||
"len": 66608
|
||||
},
|
||||
"assets/images/blog/a1ee6dcf-55ef-43cd-ae05-682d2e28e932-w960-h720.jpg": {
|
||||
"filename": "assets/images/blog/a1ee6dcf-55ef-43cd-ae05-682d2e28e932-w960-h720.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2451031,
|
||||
"len": 23239
|
||||
},
|
||||
"assets/images/blog/a1ee6dcf-55ef-43cd-ae05-682d2e28e932.jpg": {
|
||||
"filename": "assets/images/blog/a1ee6dcf-55ef-43cd-ae05-682d2e28e932.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2474270,
|
||||
"len": 82334
|
||||
},
|
||||
"assets/images/blog/content/17343f27-a62f-4193-a0e5-4190d948eb2e.png": {
|
||||
"filename": "assets/images/blog/content/17343f27-a62f-4193-a0e5-4190d948eb2e.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 2556604,
|
||||
"len": 8571
|
||||
},
|
||||
"assets/images/blog/content/1748cc9c-9ea0-47b8-a110-ad3a114408d1.png": {
|
||||
"filename": "assets/images/blog/content/1748cc9c-9ea0-47b8-a110-ad3a114408d1.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 2565175,
|
||||
"len": 19776
|
||||
},
|
||||
"assets/images/blog/content/27b98c5e-ba57-47e6-9fe7-9b82fb89868b.jpg": {
|
||||
"filename": "assets/images/blog/content/27b98c5e-ba57-47e6-9fe7-9b82fb89868b.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2584951,
|
||||
"len": 68054
|
||||
},
|
||||
"assets/images/blog/content/39374de9-f24a-46f6-9955-982687607c6d.png": {
|
||||
"filename": "assets/images/blog/content/39374de9-f24a-46f6-9955-982687607c6d.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 2653005,
|
||||
"len": 30305
|
||||
},
|
||||
"assets/images/blog/content/5c660f5c-04fb-46cd-9846-edccb9a7b778.jpg": {
|
||||
"filename": "assets/images/blog/content/5c660f5c-04fb-46cd-9846-edccb9a7b778.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2683310,
|
||||
"len": 10409
|
||||
},
|
||||
"assets/images/blog/content/5cb6fb87-75d0-4aa4-99c7-b7815ca7ea70.png": {
|
||||
"filename": "assets/images/blog/content/5cb6fb87-75d0-4aa4-99c7-b7815ca7ea70.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 2693719,
|
||||
"len": 123977
|
||||
},
|
||||
"assets/images/blog/content/765827f6-192b-48c9-b3e1-cb7b33e3b881.png": {
|
||||
"filename": "assets/images/blog/content/765827f6-192b-48c9-b3e1-cb7b33e3b881.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 2817696,
|
||||
"len": 110297
|
||||
},
|
||||
"assets/images/blog/content/7b39a2f8-8060-43e7-a439-43f799d3e069.jpg": {
|
||||
"filename": "assets/images/blog/content/7b39a2f8-8060-43e7-a439-43f799d3e069.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 2927993,
|
||||
"len": 24372
|
||||
},
|
||||
"assets/images/blog/content/8af4faff-e011-4e31-ba28-5023f65d1003.png": {
|
||||
"filename": "assets/images/blog/content/8af4faff-e011-4e31-ba28-5023f65d1003.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 2952365,
|
||||
"len": 106400
|
||||
},
|
||||
"assets/images/blog/content/ae29cd58-f28f-4a0e-bffb-a7e4e1235797.png": {
|
||||
"filename": "assets/images/blog/content/ae29cd58-f28f-4a0e-bffb-a7e4e1235797.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 3058765,
|
||||
"len": 33357
|
||||
},
|
||||
"assets/images/blog/content/b3be6c1c-725a-4af2-a85f-e47e09bbceef.png": {
|
||||
"filename": "assets/images/blog/content/b3be6c1c-725a-4af2-a85f-e47e09bbceef.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 3092122,
|
||||
"len": 37074
|
||||
},
|
||||
"assets/images/blog/content/b4e772a3-effb-4a5d-82d9-db9596ccfe51.png": {
|
||||
"filename": "assets/images/blog/content/b4e772a3-effb-4a5d-82d9-db9596ccfe51.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 3129196,
|
||||
"len": 79662
|
||||
},
|
||||
"assets/images/blog/content/d2731109-b50f-4c1f-b4f9-7ab8cac196da.png": {
|
||||
"filename": "assets/images/blog/content/d2731109-b50f-4c1f-b4f9-7ab8cac196da.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 3208858,
|
||||
"len": 104535
|
||||
},
|
||||
"assets/images/blog/content/fed0e592-d063-497b-9a3b-2bfc29b04d1a.jpg": {
|
||||
"filename": "assets/images/blog/content/fed0e592-d063-497b-9a3b-2bfc29b04d1a.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 3313393,
|
||||
"len": 9535
|
||||
},
|
||||
"assets/images/blog/e4956336-3662-46ae-bea2-7fd3059919c3-w1920-h1440.jpg": {
|
||||
"filename": "assets/images/blog/e4956336-3662-46ae-bea2-7fd3059919c3-w1920-h1440.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 3322928,
|
||||
"len": 402770
|
||||
},
|
||||
"assets/images/blog/e4956336-3662-46ae-bea2-7fd3059919c3-w960-h720.jpg": {
|
||||
"filename": "assets/images/blog/e4956336-3662-46ae-bea2-7fd3059919c3-w960-h720.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 3725698,
|
||||
"len": 143539
|
||||
},
|
||||
"assets/images/blog/e4956336-3662-46ae-bea2-7fd3059919c3.jpg": {
|
||||
"filename": "assets/images/blog/e4956336-3662-46ae-bea2-7fd3059919c3.jpg",
|
||||
"contenttype": "image/jpeg",
|
||||
"offset": 3869237,
|
||||
"len": 375170
|
||||
},
|
||||
"assets/images/logo.svg": {
|
||||
"filename": "assets/images/logo.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 4244407,
|
||||
"len": 2183
|
||||
},
|
||||
"assets/js/themes.js": {
|
||||
"filename": "assets/js/themes.js",
|
||||
"contenttype": "text/javascript",
|
||||
"offset": 4246590,
|
||||
"len": 779
|
||||
},
|
||||
"blog/building_a_web_farm_with_docker_and_raspberry_pi.html": {
|
||||
"filename": "blog/building_a_web_farm_with_docker_and_raspberry_pi.html",
|
||||
"contenttype": "text/html",
|
||||
"offset": 4247369,
|
||||
"len": 23111
|
||||
},
|
||||
"blog/continuously_deploy_a_static_website_with_azure_pipelines.html": {
|
||||
"filename": "blog/continuously_deploy_a_static_website_with_azure_pipelines.html",
|
||||
"contenttype": "text/html",
|
||||
"offset": 4270480,
|
||||
"len": 24738
|
||||
},
|
||||
"blog/decentralise_your_website_as_much_as_possible.html": {
|
||||
"filename": "blog/decentralise_your_website_as_much_as_possible.html",
|
||||
"contenttype": "text/html",
|
||||
"offset": 4295218,
|
||||
"len": 14825
|
||||
},
|
||||
"blog/developing_smart_contracts_for_business.html": {
|
||||
"filename": "blog/developing_smart_contracts_for_business.html",
|
||||
"contenttype": "text/html",
|
||||
"offset": 4310043,
|
||||
"len": 25783
|
||||
},
|
||||
"blog/getting_to_grips_with_jwt_in_asp_net_core.html": {
|
||||
"filename": "blog/getting_to_grips_with_jwt_in_asp_net_core.html",
|
||||
"contenttype": "text/html",
|
||||
"offset": 4335826,
|
||||
"len": 20915
|
||||
},
|
||||
"blog/index.html": { "filename": "blog/index.html", "contenttype": "text/html", "offset": 4356741, "len": 7345 },
|
||||
"blog/setting_up_an_asp_net_core_web_farm.html": {
|
||||
"filename": "blog/setting_up_an_asp_net_core_web_farm.html",
|
||||
"contenttype": "text/html",
|
||||
"offset": 4364086,
|
||||
"len": 11464
|
||||
},
|
||||
"favicon-16x16.png": { "filename": "favicon-16x16.png", "contenttype": "image/png", "offset": 4375550, "len": 430 },
|
||||
"favicon-32x32.png": { "filename": "favicon-32x32.png", "contenttype": "image/png", "offset": 4375980, "len": 540 },
|
||||
"favicon.ico": { "filename": "favicon.ico", "contenttype": "image/x-icon", "offset": 4376520, "len": 15086 },
|
||||
"feed.atom": {
|
||||
"filename": "feed.atom",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 4391606,
|
||||
"len": 95092
|
||||
},
|
||||
"index.html": { "filename": "index.html", "contenttype": "text/html", "offset": 4486698, "len": 4981 }
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
{
|
||||
"filename": "skygallery-v0.1.1-76c4c115fcb526716b2564568850f433",
|
||||
"subfiles": {
|
||||
"css/app.84a130ed.css": { "filename": "css/app.84a130ed.css", "contenttype": "text/css", "len": 698 },
|
||||
"css/chunk-5ce44031.d4e78528.css": {
|
||||
"filename": "css/chunk-5ce44031.d4e78528.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 698,
|
||||
"len": 45
|
||||
},
|
||||
"css/chunk-6bef839b.593aa2be.css": {
|
||||
"filename": "css/chunk-6bef839b.593aa2be.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 743,
|
||||
"len": 5013
|
||||
},
|
||||
"css/chunk-8ed50a48.8ba8c09d.css": {
|
||||
"filename": "css/chunk-8ed50a48.8ba8c09d.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 5756,
|
||||
"len": 7204
|
||||
},
|
||||
"css/chunk-eb4c1efc.2a7e25ed.css": {
|
||||
"filename": "css/chunk-eb4c1efc.2a7e25ed.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 12960,
|
||||
"len": 45
|
||||
},
|
||||
"css/chunk-vendors.b4f58487.css": {
|
||||
"filename": "css/chunk-vendors.b4f58487.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 13005,
|
||||
"len": 382063
|
||||
},
|
||||
"img/skygallery_logo.2336197e.svg": {
|
||||
"filename": "img/skygallery_logo.2336197e.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 395068,
|
||||
"len": 923
|
||||
},
|
||||
"img/skynet-logo-animated.4d24345c.svg": {
|
||||
"filename": "img/skynet-logo-animated.4d24345c.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 395991,
|
||||
"len": 2600
|
||||
},
|
||||
"index.html": { "filename": "index.html", "contenttype": "text/html", "offset": 398591, "len": 2534 },
|
||||
"js/app.cff1e0a4.js": {
|
||||
"filename": "js/app.cff1e0a4.js",
|
||||
"contenttype": "application/javascript",
|
||||
"offset": 401125,
|
||||
"len": 15604
|
||||
},
|
||||
"js/app.cff1e0a4.js.map": {
|
||||
"filename": "js/app.cff1e0a4.js.map",
|
||||
"contenttype": "application/json",
|
||||
"offset": 416729,
|
||||
"len": 54424
|
||||
},
|
||||
"js/chunk-5ce44031.7fb55da9.js": {
|
||||
"filename": "js/chunk-5ce44031.7fb55da9.js",
|
||||
"contenttype": "application/javascript",
|
||||
"offset": 471153,
|
||||
"len": 3644
|
||||
},
|
||||
"js/chunk-5ce44031.7fb55da9.js.map": {
|
||||
"filename": "js/chunk-5ce44031.7fb55da9.js.map",
|
||||
"contenttype": "application/json",
|
||||
"offset": 474797,
|
||||
"len": 13494
|
||||
},
|
||||
"js/chunk-6bef839b.b543fe7d.js": {
|
||||
"filename": "js/chunk-6bef839b.b543fe7d.js",
|
||||
"contenttype": "application/javascript",
|
||||
"offset": 488291,
|
||||
"len": 13349
|
||||
},
|
||||
"js/chunk-6bef839b.b543fe7d.js.map": {
|
||||
"filename": "js/chunk-6bef839b.b543fe7d.js.map",
|
||||
"contenttype": "application/json",
|
||||
"offset": 501640,
|
||||
"len": 46690
|
||||
},
|
||||
"js/chunk-8ed50a48.35f8ef35.js": {
|
||||
"filename": "js/chunk-8ed50a48.35f8ef35.js",
|
||||
"contenttype": "application/javascript",
|
||||
"offset": 548330,
|
||||
"len": 130329
|
||||
},
|
||||
"js/chunk-8ed50a48.35f8ef35.js.map": {
|
||||
"filename": "js/chunk-8ed50a48.35f8ef35.js.map",
|
||||
"contenttype": "application/json",
|
||||
"offset": 678659,
|
||||
"len": 507145
|
||||
},
|
||||
"js/chunk-eb4c1efc.57b6e01c.js": {
|
||||
"filename": "js/chunk-eb4c1efc.57b6e01c.js",
|
||||
"contenttype": "application/javascript",
|
||||
"offset": 1185804,
|
||||
"len": 4407
|
||||
},
|
||||
"js/chunk-eb4c1efc.57b6e01c.js.map": {
|
||||
"filename": "js/chunk-eb4c1efc.57b6e01c.js.map",
|
||||
"contenttype": "application/json",
|
||||
"offset": 1190211,
|
||||
"len": 15355
|
||||
},
|
||||
"js/chunk-vendors.1fd55121.js": {
|
||||
"filename": "js/chunk-vendors.1fd55121.js",
|
||||
"contenttype": "application/javascript",
|
||||
"offset": 1205566,
|
||||
"len": 749829
|
||||
},
|
||||
"js/chunk-vendors.1fd55121.js.map": {
|
||||
"filename": "js/chunk-vendors.1fd55121.js.map",
|
||||
"contenttype": "application/json",
|
||||
"offset": 1955395,
|
||||
"len": 2793251
|
||||
}
|
||||
},
|
||||
"defaultpath": "/index.html"
|
||||
}
|
|
@ -1,658 +0,0 @@
|
|||
{
|
||||
"filename": "build",
|
||||
"subfiles": {
|
||||
"451.html": { "filename": "451.html", "contenttype": "text/html", "offset": 20181232, "len": 200 },
|
||||
"asset-manifest.json": {
|
||||
"filename": "asset-manifest.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 485031,
|
||||
"len": 4561
|
||||
},
|
||||
"favicon.png": { "filename": "favicon.png", "contenttype": "image/png", "offset": 489592, "len": 7072 },
|
||||
"images/192x192_App_Icon.png": {
|
||||
"filename": "images/192x192_App_Icon.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 434153,
|
||||
"len": 50878
|
||||
},
|
||||
"images/512x512_App_Icon.png": {
|
||||
"filename": "images/512x512_App_Icon.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 47542,
|
||||
"len": 386611
|
||||
},
|
||||
"index.html": { "filename": "index.html", "contenttype": "text/html", "len": 3268 },
|
||||
"locales/de.json": {
|
||||
"filename": "locales/de.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 7491,
|
||||
"len": 4376
|
||||
},
|
||||
"locales/en.json": {
|
||||
"filename": "locales/en.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 23709,
|
||||
"len": 4321
|
||||
},
|
||||
"locales/es-AR.json": {
|
||||
"filename": "locales/es-AR.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 16866,
|
||||
"len": 3624
|
||||
},
|
||||
"locales/es-US.json": {
|
||||
"filename": "locales/es-US.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 43912,
|
||||
"len": 3630
|
||||
},
|
||||
"locales/it-IT.json": {
|
||||
"filename": "locales/it-IT.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 3268,
|
||||
"len": 4223
|
||||
},
|
||||
"locales/iw.json": {
|
||||
"filename": "locales/iw.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 28030,
|
||||
"len": 3929
|
||||
},
|
||||
"locales/ro.json": {
|
||||
"filename": "locales/ro.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 31959,
|
||||
"len": 3794
|
||||
},
|
||||
"locales/ru.json": {
|
||||
"filename": "locales/ru.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 11867,
|
||||
"len": 4999
|
||||
},
|
||||
"locales/vi.json": {
|
||||
"filename": "locales/vi.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 39011,
|
||||
"len": 4901
|
||||
},
|
||||
"locales/zh-CN.json": {
|
||||
"filename": "locales/zh-CN.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 20490,
|
||||
"len": 3219
|
||||
},
|
||||
"locales/zh-TW.json": {
|
||||
"filename": "locales/zh-TW.json",
|
||||
"contenttype": "application/json",
|
||||
"offset": 35753,
|
||||
"len": 3258
|
||||
},
|
||||
"manifest.json": { "filename": "manifest.json", "contenttype": "application/json", "offset": 20190818, "len": 470 },
|
||||
"precache-manifest.5ce41899d70d2e0450f591b3e917c2a4.js": {
|
||||
"filename": "precache-manifest.5ce41899d70d2e0450f591b3e917c2a4.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 20181432,
|
||||
"len": 9386
|
||||
},
|
||||
"service-worker.js": {
|
||||
"filename": "service-worker.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 20191288,
|
||||
"len": 1183
|
||||
},
|
||||
"static/css/4.f04942fe.chunk.css": {
|
||||
"filename": "static/css/4.f04942fe.chunk.css",
|
||||
"contenttype": "text/css",
|
||||
"offset": 496664,
|
||||
"len": 5331
|
||||
},
|
||||
"static/css/4.f04942fe.chunk.css.map": {
|
||||
"filename": "static/css/4.f04942fe.chunk.css.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 501995,
|
||||
"len": 8394
|
||||
},
|
||||
"static/js/0.1043efff.chunk.js": {
|
||||
"filename": "static/js/0.1043efff.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 3451819,
|
||||
"len": 226756
|
||||
},
|
||||
"static/js/0.1043efff.chunk.js.map": {
|
||||
"filename": "static/js/0.1043efff.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 8495570,
|
||||
"len": 811341
|
||||
},
|
||||
"static/js/1.722d768c.chunk.js": {
|
||||
"filename": "static/js/1.722d768c.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 2503781,
|
||||
"len": 20289
|
||||
},
|
||||
"static/js/1.722d768c.chunk.js.map": {
|
||||
"filename": "static/js/1.722d768c.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 11896220,
|
||||
"len": 44729
|
||||
},
|
||||
"static/js/4.cebcd4f8.chunk.js": {
|
||||
"filename": "static/js/4.cebcd4f8.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 11941212,
|
||||
"len": 1486762
|
||||
},
|
||||
"static/js/4.cebcd4f8.chunk.js.LICENSE.txt": {
|
||||
"filename": "static/js/4.cebcd4f8.chunk.js.LICENSE.txt",
|
||||
"contenttype": "text/plain",
|
||||
"offset": 14378677,
|
||||
"len": 3519
|
||||
},
|
||||
"static/js/4.cebcd4f8.chunk.js.map": {
|
||||
"filename": "static/js/4.cebcd4f8.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 3678575,
|
||||
"len": 4816995
|
||||
},
|
||||
"static/js/5.428f04e8.chunk.js": {
|
||||
"filename": "static/js/5.428f04e8.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 1887438,
|
||||
"len": 616343
|
||||
},
|
||||
"static/js/5.428f04e8.chunk.js.LICENSE.txt": {
|
||||
"filename": "static/js/5.428f04e8.chunk.js.LICENSE.txt",
|
||||
"contenttype": "text/plain",
|
||||
"offset": 3450983,
|
||||
"len": 426
|
||||
},
|
||||
"static/js/5.428f04e8.chunk.js.map": {
|
||||
"filename": "static/js/5.428f04e8.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 10046674,
|
||||
"len": 1553345
|
||||
},
|
||||
"static/js/6.29fcca22.chunk.js": {
|
||||
"filename": "static/js/6.29fcca22.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 11600019,
|
||||
"len": 296095
|
||||
},
|
||||
"static/js/6.29fcca22.chunk.js.map": {
|
||||
"filename": "static/js/6.29fcca22.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 13440646,
|
||||
"len": 938031
|
||||
},
|
||||
"static/js/7.8d2bc3b4.chunk.js": {
|
||||
"filename": "static/js/7.8d2bc3b4.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 9306911,
|
||||
"len": 263
|
||||
},
|
||||
"static/js/7.8d2bc3b4.chunk.js.map": {
|
||||
"filename": "static/js/7.8d2bc3b4.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 11896114,
|
||||
"len": 106
|
||||
},
|
||||
"static/js/8.3d784f08.chunk.js": {
|
||||
"filename": "static/js/8.3d784f08.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 11940949,
|
||||
"len": 263
|
||||
},
|
||||
"static/js/8.3d784f08.chunk.js.map": {
|
||||
"filename": "static/js/8.3d784f08.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 3450877,
|
||||
"len": 106
|
||||
},
|
||||
"static/js/9.08920d68.chunk.js": {
|
||||
"filename": "static/js/9.08920d68.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 2524070,
|
||||
"len": 626875
|
||||
},
|
||||
"static/js/9.08920d68.chunk.js.LICENSE.txt": {
|
||||
"filename": "static/js/9.08920d68.chunk.js.LICENSE.txt",
|
||||
"contenttype": "text/plain",
|
||||
"offset": 3451409,
|
||||
"len": 410
|
||||
},
|
||||
"static/js/9.08920d68.chunk.js.map": {
|
||||
"filename": "static/js/9.08920d68.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 512852,
|
||||
"len": 1374586
|
||||
},
|
||||
"static/js/main.d2a5ca05.chunk.js": {
|
||||
"filename": "static/js/main.d2a5ca05.chunk.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 3150945,
|
||||
"len": 299932
|
||||
},
|
||||
"static/js/main.d2a5ca05.chunk.js.map": {
|
||||
"filename": "static/js/main.d2a5ca05.chunk.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 9307174,
|
||||
"len": 739500
|
||||
},
|
||||
"static/js/runtime-main.712341b8.js": {
|
||||
"filename": "static/js/runtime-main.712341b8.js",
|
||||
"contenttype": "application/x-javascript",
|
||||
"offset": 510389,
|
||||
"len": 2463
|
||||
},
|
||||
"static/js/runtime-main.712341b8.js.map": {
|
||||
"filename": "static/js/runtime-main.712341b8.js.map",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 13427974,
|
||||
"len": 12672
|
||||
},
|
||||
"static/media/Inter-Black.09f4068b.woff2": {
|
||||
"filename": "static/media/Inter-Black.09f4068b.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16311114,
|
||||
"len": 104656
|
||||
},
|
||||
"static/media/Inter-Black.e3735483.woff": {
|
||||
"filename": "static/media/Inter-Black.e3735483.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16415770,
|
||||
"len": 139648
|
||||
},
|
||||
"static/media/Inter-BlackItalic.07e69b53.woff": {
|
||||
"filename": "static/media/Inter-BlackItalic.07e69b53.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 15020483,
|
||||
"len": 145816
|
||||
},
|
||||
"static/media/Inter-BlackItalic.daa1ca3c.woff2": {
|
||||
"filename": "static/media/Inter-BlackItalic.daa1ca3c.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19675808,
|
||||
"len": 109900
|
||||
},
|
||||
"static/media/Inter-Bold.79260e5b.woff": {
|
||||
"filename": "static/media/Inter-Bold.79260e5b.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 15781749,
|
||||
"len": 143464
|
||||
},
|
||||
"static/media/Inter-Bold.aed27700.woff2": {
|
||||
"filename": "static/media/Inter-Bold.aed27700.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16555739,
|
||||
"len": 107144
|
||||
},
|
||||
"static/media/Inter-BoldItalic.8ef77a03.woff2": {
|
||||
"filename": "static/media/Inter-BoldItalic.8ef77a03.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 17104768,
|
||||
"len": 112276
|
||||
},
|
||||
"static/media/Inter-BoldItalic.e0879d64.woff": {
|
||||
"filename": "static/media/Inter-BoldItalic.e0879d64.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 15483981,
|
||||
"len": 149360
|
||||
},
|
||||
"static/media/Inter-ExtraBold.38bc51bc.woff": {
|
||||
"filename": "static/media/Inter-ExtraBold.38bc51bc.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19419594,
|
||||
"len": 143256
|
||||
},
|
||||
"static/media/Inter-ExtraBold.92d16aee.woff2": {
|
||||
"filename": "static/media/Inter-ExtraBold.92d16aee.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19312290,
|
||||
"len": 107304
|
||||
},
|
||||
"static/media/Inter-ExtraBoldItalic.0e4b21eb.woff": {
|
||||
"filename": "static/media/Inter-ExtraBoldItalic.0e4b21eb.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16671312,
|
||||
"len": 149116
|
||||
},
|
||||
"static/media/Inter-ExtraBoldItalic.57ea76d0.woff2": {
|
||||
"filename": "static/media/Inter-ExtraBoldItalic.57ea76d0.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18732262,
|
||||
"len": 112656
|
||||
},
|
||||
"static/media/Inter-ExtraLight.4bd040df.woff": {
|
||||
"filename": "static/media/Inter-ExtraLight.4bd040df.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 14746958,
|
||||
"len": 141344
|
||||
},
|
||||
"static/media/Inter-ExtraLight.4d9f96f8.woff2": {
|
||||
"filename": "static/media/Inter-ExtraLight.4d9f96f8.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18945450,
|
||||
"len": 105444
|
||||
},
|
||||
"static/media/Inter-ExtraLightItalic.54d3d9a5.woff2": {
|
||||
"filename": "static/media/Inter-ExtraLightItalic.54d3d9a5.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 14888302,
|
||||
"len": 111804
|
||||
},
|
||||
"static/media/Inter-ExtraLightItalic.84c26656.woff": {
|
||||
"filename": "static/media/Inter-ExtraLightItalic.84c26656.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18569981,
|
||||
"len": 148416
|
||||
},
|
||||
"static/media/Inter-Italic.9528384c.woff2": {
|
||||
"filename": "static/media/Inter-Italic.9528384c.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 14383371,
|
||||
"len": 108172
|
||||
},
|
||||
"static/media/Inter-Italic.e4ad3666.woff": {
|
||||
"filename": "static/media/Inter-Italic.e4ad3666.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 20037756,
|
||||
"len": 143476
|
||||
},
|
||||
"static/media/Inter-Light.5baca21a.woff2": {
|
||||
"filename": "static/media/Inter-Light.5baca21a.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18016306,
|
||||
"len": 105556
|
||||
},
|
||||
"static/media/Inter-Light.b9920de0.woff": {
|
||||
"filename": "static/media/Inter-Light.b9920de0.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18428717,
|
||||
"len": 141264
|
||||
},
|
||||
"static/media/Inter-LightItalic.0555a46c.woff": {
|
||||
"filename": "static/media/Inter-LightItalic.0555a46c.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 15633341,
|
||||
"len": 148408
|
||||
},
|
||||
"static/media/Inter-LightItalic.adc70179.woff2": {
|
||||
"filename": "static/media/Inter-LightItalic.adc70179.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19200250,
|
||||
"len": 112040
|
||||
},
|
||||
"static/media/Inter-Medium.7a8cc724.woff": {
|
||||
"filename": "static/media/Inter-Medium.7a8cc724.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 17763598,
|
||||
"len": 142780
|
||||
},
|
||||
"static/media/Inter-Medium.f6cf0a0b.woff2": {
|
||||
"filename": "static/media/Inter-Medium.f6cf0a0b.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 17431014,
|
||||
"len": 106484
|
||||
},
|
||||
"static/media/Inter-MediumItalic.417907d2.woff": {
|
||||
"filename": "static/media/Inter-MediumItalic.417907d2.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16955424,
|
||||
"len": 149344
|
||||
},
|
||||
"static/media/Inter-MediumItalic.565a7104.woff2": {
|
||||
"filename": "static/media/Inter-MediumItalic.565a7104.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 17318374,
|
||||
"len": 112640
|
||||
},
|
||||
"static/media/Inter-Regular.4dd66a11.woff2": {
|
||||
"filename": "static/media/Inter-Regular.4dd66a11.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18844918,
|
||||
"len": 100368
|
||||
},
|
||||
"static/media/Inter-Regular.7c539936.woff": {
|
||||
"filename": "static/media/Inter-Regular.7c539936.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16820428,
|
||||
"len": 134996
|
||||
},
|
||||
"static/media/Inter-SemiBold.1db6c55c.woff": {
|
||||
"filename": "static/media/Inter-SemiBold.1db6c55c.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19785708,
|
||||
"len": 143148
|
||||
},
|
||||
"static/media/Inter-SemiBold.dd8a55ef.woff2": {
|
||||
"filename": "static/media/Inter-SemiBold.dd8a55ef.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 14491543,
|
||||
"len": 106916
|
||||
},
|
||||
"static/media/Inter-SemiBoldItalic.81678d1a.woff": {
|
||||
"filename": "static/media/Inter-SemiBoldItalic.81678d1a.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19050894,
|
||||
"len": 149356
|
||||
},
|
||||
"static/media/Inter-SemiBoldItalic.ac201e30.woff2": {
|
||||
"filename": "static/media/Inter-SemiBoldItalic.ac201e30.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19562850,
|
||||
"len": 112768
|
||||
},
|
||||
"static/media/Inter-Thin.850febbe.woff2": {
|
||||
"filename": "static/media/Inter-Thin.850febbe.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 17217044,
|
||||
"len": 101004
|
||||
},
|
||||
"static/media/Inter-Thin.ead42837.woff": {
|
||||
"filename": "static/media/Inter-Thin.ead42837.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 18230961,
|
||||
"len": 137068
|
||||
},
|
||||
"static/media/Inter-ThinItalic.a76db065.woff": {
|
||||
"filename": "static/media/Inter-ThinItalic.a76db065.woff",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 16166265,
|
||||
"len": 144528
|
||||
},
|
||||
"static/media/Inter-ThinItalic.e08d9b2a.woff2": {
|
||||
"filename": "static/media/Inter-ThinItalic.e08d9b2a.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 19930172,
|
||||
"len": 107584
|
||||
},
|
||||
"static/media/Inter-italic.var.2690e3c2.woff2": {
|
||||
"filename": "static/media/Inter-italic.var.2690e3c2.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 15925213,
|
||||
"len": 241052
|
||||
},
|
||||
"static/media/Inter-roman.var.90e8f61d.woff2": {
|
||||
"filename": "static/media/Inter-roman.var.90e8f61d.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 17537498,
|
||||
"len": 226100
|
||||
},
|
||||
"static/media/Inter.var.4b976905.woff2": {
|
||||
"filename": "static/media/Inter.var.4b976905.woff2",
|
||||
"contenttype": "application/octet-stream",
|
||||
"offset": 15166461,
|
||||
"len": 317520
|
||||
},
|
||||
"static/media/arrow-down-blue.cd061363.svg": {
|
||||
"filename": "static/media/arrow-down-blue.cd061363.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 17318048,
|
||||
"len": 326
|
||||
},
|
||||
"static/media/arrow-down-grey.c0dedd2f.svg": {
|
||||
"filename": "static/media/arrow-down-grey.c0dedd2f.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 15000106,
|
||||
"len": 326
|
||||
},
|
||||
"static/media/arrow-right-white.337ad716.png": {
|
||||
"filename": "static/media/arrow-right-white.337ad716.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 15000432,
|
||||
"len": 12999
|
||||
},
|
||||
"static/media/arrow-right.d285b6cf.svg": {
|
||||
"filename": "static/media/arrow-right.d285b6cf.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 19929626,
|
||||
"len": 263
|
||||
},
|
||||
"static/media/blue-loader.904b44c2.svg": {
|
||||
"filename": "static/media/blue-loader.904b44c2.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 19929889,
|
||||
"len": 283
|
||||
},
|
||||
"static/media/circle-grey.ed2a1dad.svg": {
|
||||
"filename": "static/media/circle-grey.ed2a1dad.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 16310793,
|
||||
"len": 321
|
||||
},
|
||||
"static/media/circle.2d975615.svg": {
|
||||
"filename": "static/media/circle.2d975615.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 16555418,
|
||||
"len": 321
|
||||
},
|
||||
"static/media/coinbaseWalletIcon.62578f59.svg": {
|
||||
"filename": "static/media/coinbaseWalletIcon.62578f59.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 18375091,
|
||||
"len": 53626
|
||||
},
|
||||
"static/media/dropdown-blue.b20914ec.svg": {
|
||||
"filename": "static/media/dropdown-blue.b20914ec.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14382513,
|
||||
"len": 164
|
||||
},
|
||||
"static/media/dropdown.7d32d2fa.svg": {
|
||||
"filename": "static/media/dropdown.7d32d2fa.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 18945286,
|
||||
"len": 164
|
||||
},
|
||||
"static/media/dropup-blue.b96d70e1.svg": {
|
||||
"filename": "static/media/dropup-blue.b96d70e1.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 15166299,
|
||||
"len": 162
|
||||
},
|
||||
"static/media/link.50c67f3c.svg": {
|
||||
"filename": "static/media/link.50c67f3c.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14382196,
|
||||
"len": 317
|
||||
},
|
||||
"static/media/logo.5827780d.svg": {
|
||||
"filename": "static/media/logo.5827780d.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 15013431,
|
||||
"len": 7052
|
||||
},
|
||||
"static/media/logo_white.edb44e56.svg": {
|
||||
"filename": "static/media/logo_white.edb44e56.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 18368029,
|
||||
"len": 7062
|
||||
},
|
||||
"static/media/magnifying-glass.67440097.svg": {
|
||||
"filename": "static/media/magnifying-glass.67440097.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 16662883,
|
||||
"len": 8429
|
||||
},
|
||||
"static/media/menu.4f2c4440.svg": {
|
||||
"filename": "static/media/menu.4f2c4440.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 18015579,
|
||||
"len": 727
|
||||
},
|
||||
"static/media/metamask.023762b6.png": {
|
||||
"filename": "static/media/metamask.023762b6.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 14611832,
|
||||
"len": 114217
|
||||
},
|
||||
"static/media/plus-blue.e8021e51.svg": {
|
||||
"filename": "static/media/plus-blue.e8021e51.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14746469,
|
||||
"len": 190
|
||||
},
|
||||
"static/media/plus-grey.d8e0be7d.svg": {
|
||||
"filename": "static/media/plus-grey.d8e0be7d.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 19675618,
|
||||
"len": 190
|
||||
},
|
||||
"static/media/portisIcon.b234b2bf.png": {
|
||||
"filename": "static/media/portisIcon.b234b2bf.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 18718397,
|
||||
"len": 13865
|
||||
},
|
||||
"static/media/question-mark.1ae4d9f4.svg": {
|
||||
"filename": "static/media/question-mark.1ae4d9f4.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14726049,
|
||||
"len": 818
|
||||
},
|
||||
"static/media/question.a46e8bc1.svg": {
|
||||
"filename": "static/media/question.a46e8bc1.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 19928856,
|
||||
"len": 770
|
||||
},
|
||||
"static/media/spinner.be00fc4a.svg": {
|
||||
"filename": "static/media/spinner.be00fc4a.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14382677,
|
||||
"len": 694
|
||||
},
|
||||
"static/media/trustWallet.edcc1ab5.png": {
|
||||
"filename": "static/media/trustWallet.edcc1ab5.png",
|
||||
"contenttype": "image/png",
|
||||
"offset": 14726867,
|
||||
"len": 19602
|
||||
},
|
||||
"static/media/walletConnectIcon.8215855c.svg": {
|
||||
"filename": "static/media/walletConnectIcon.8215855c.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14598459,
|
||||
"len": 13373
|
||||
},
|
||||
"static/media/wordmark.b75565ae.svg": {
|
||||
"filename": "static/media/wordmark.b75565ae.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 18121862,
|
||||
"len": 109099
|
||||
},
|
||||
"static/media/wordmark_white.9914390f.svg": {
|
||||
"filename": "static/media/wordmark_white.9914390f.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 17906378,
|
||||
"len": 109201
|
||||
},
|
||||
"static/media/x.5b8e2186.svg": {
|
||||
"filename": "static/media/x.5b8e2186.svg",
|
||||
"contenttype": "image/svg+xml",
|
||||
"offset": 14746659,
|
||||
"len": 299
|
||||
}
|
||||
},
|
||||
"defaultpath": "/index.html"
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
process.env.NODE_ENV = process.env.NODE_ENV || "development";
|
||||
|
||||
if (!process.env.PORTAL_DOMAIN) {
|
||||
throw new Error("You need to provide PORTAL_DOMAIN environment variable");
|
||||
}
|
||||
|
||||
if (process.env.ACCOUNTS_ENABLED === "true") {
|
||||
if (["authenticated", "subscription"].includes(process.env.ACCOUNTS_LIMIT_ACCESS)) {
|
||||
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 db = require("./db");
|
||||
|
||||
const host = process.env.HOSTNAME || "0.0.0.0";
|
||||
const port = Number(process.env.PORT) || 3100;
|
||||
|
||||
const server = express();
|
||||
|
||||
server.use(express.urlencoded({ extended: false }));
|
||||
server.use(express.json());
|
||||
server.use((req, res, next) => {
|
||||
db.read();
|
||||
next();
|
||||
});
|
||||
|
||||
server.get("/health-check", require("./api/index"));
|
||||
server.get("/health-check/critical", require("./api/critical"));
|
||||
server.get("/health-check/extended", require("./api/extended"));
|
||||
server.get("/health-check/disabled", require("./api/disabled"));
|
||||
|
||||
server.listen(port, host, (error) => {
|
||||
if (error) throw error;
|
||||
|
||||
console.info(`Server listening at http://${host}:${port} (NODE_ENV: ${process.env.NODE_ENV})`);
|
||||
|
||||
const { ipRegex } = require("./utils");
|
||||
|
||||
if (ipRegex.test(process.env.serverip)) {
|
||||
console.info(`Server public ip: ${process.env.serverip}`);
|
||||
}
|
||||
});
|
|
@ -1,144 +0,0 @@
|
|||
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,
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
describe("ipRegex", () => {
|
||||
const { ipRegex } = require("./utils");
|
||||
|
||||
test("should test true for valid ip", () => {
|
||||
expect(ipRegex.test("8.8.8.8")).toEqual(true);
|
||||
expect(ipRegex.test("127.0.0.1")).toEqual(true);
|
||||
expect(ipRegex.test("192.168.0.1")).toEqual(true);
|
||||
expect(ipRegex.test("10.10.10.10")).toEqual(true);
|
||||
expect(ipRegex.test("135.124.12.47")).toEqual(true);
|
||||
});
|
||||
|
||||
test("should test false for invalid ip", () => {
|
||||
expect(ipRegex.test("888.8.8.8")).toEqual(false);
|
||||
expect(ipRegex.test("....")).toEqual(false);
|
||||
expect(ipRegex.test(null)).toEqual(false);
|
||||
expect(ipRegex.test("foo")).toEqual(false);
|
||||
expect(ipRegex.test("")).toEqual(false);
|
||||
});
|
||||
});
|
|
@ -1,18 +0,0 @@
|
|||
const http = require("http");
|
||||
const { ipCheckService, ipRegex } = require("./utils");
|
||||
|
||||
const request = http.request({ host: ipCheckService }, (response) => {
|
||||
response.on("data", (data) => {
|
||||
if (ipRegex.test(data)) {
|
||||
process.stdout.write(data);
|
||||
} else {
|
||||
throw new Error(`${ipCheckService} responded with invalid ip: "${data}"`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
request.on("error", (error) => {
|
||||
throw error; // throw error to exit with code 1
|
||||
});
|
||||
|
||||
request.end();
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue