feat: fix missing import in ESM

This commit is contained in:
Eli Bosley
2024-10-25 00:03:48 -04:00
parent 7321bd0088
commit 447cecd19d
7 changed files with 148 additions and 8 deletions

View File

@@ -31,7 +31,7 @@ Options:
--environment production/staging/development Set the working environment.
--log-level ALL/TRACE/DEBUG/INFO/WARN/ERROR/FATAL/MARK/OFF Set the log level.
Copyright © 2022 Lime Technology, Inc.
Copyright © 2024 Lime Technology, Inc.
```
@@ -55,4 +55,4 @@ unraid-api report -vv
If you found this file you're likely a developer. If you'd like to know more about the API and when it's available please join [our discord](https://discord.unraid.net/).
## License
Copyright 2019-2022 Lime Technology Inc. All rights reserved.
Copyright Lime Technology Inc. All rights reserved.

View File

@@ -0,0 +1,18 @@
<?php
// Borrowed with love from https://b3z13r.wordpress.com/2011/05/16/passing-values-from-the-commandline-to-php-by-getpost-method/
// e.g. `./wrapper.php GET /tmp/random_file.php?arg1=true&arg2=a-really-long-string` { "username": "root" }
$method = $argv[1];
$query_parts = explode('?', $argv[2], 2);
$file = $query_parts[0];
$query_params = $query_parts[1];
$body = $argv[3];
// Load query_params or body into correct var
if ($method === 'GET') {
parse_str($query_params, $_GET);
} else {
parse_str($body, $_POST);
}
include($file);
?>

View File

@@ -0,0 +1,12 @@
import { logger } from '@app/core/log';
import { getters } from '@app/store';
import { type ApiKeyResponse } from '@app/graphql/generated/api/types';
import { isApiKeyValid } from '@app/store/getters/index';
export const checkApi = async (): Promise<ApiKeyResponse> => {
logger.trace('Cloud endpoint: Checking API');
const valid = isApiKeyValid();
const error = valid ? null : getters.apiKey().status;
return { valid, error };
};

View File

@@ -0,0 +1,100 @@
import { FIVE_DAYS_SECS, MOTHERSHIP_GRAPHQL_LINK, ONE_DAY_SECS } from '@app/consts';
import { logger } from '@app/core/log';
import { checkDNS } from '@app/graphql/resolvers/query/cloud/check-dns';
import { checkMothershipAuthentication } from '@app/graphql/resolvers/query/cloud/check-mothership-authentication';
import { getters, store } from '@app/store';
import { getCloudCache, getDnsCache } from '@app/store/getters';
import { setCloudCheck, setDNSCheck } from '@app/store/modules/cache';
import { got } from 'got';
import { type CloudResponse, MinigraphStatus } from '@app/graphql/generated/api/types';
import { API_VERSION } from '@app/environment';
const mothershipBaseUrl = new URL(MOTHERSHIP_GRAPHQL_LINK).origin;
const createGotOptions = (apiVersion: string, apiKey: string) => ({
timeout: {
request: 5_000,
},
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'x-unraid-api-version': apiVersion,
'x-api-key': apiKey,
},
});
/**
* This is mainly testing the user's network config
* If they cannot resolve this they may have it blocked or have a routing issue
*/
const checkCanReachMothership = async (apiVersion: string, apiKey: string): Promise<void> => {
const mothershipCanBeResolved = await got.head(mothershipBaseUrl, createGotOptions(apiVersion, apiKey)).then(() => true).catch(() => false);
if (!mothershipCanBeResolved) throw new Error(`Unable to connect to ${mothershipBaseUrl}`);
};
/**
* Run a more performant cloud check with permanent DNS checking
*/
const fastCloudCheck = async (): Promise<CloudResponse> => {
const result = { status: 'ok', error: null, ip: 'FAST_CHECK_NO_IP_FOUND' };
const cloudIp = getDnsCache()?.cloudIp ?? null;
if (cloudIp) {
result.ip = cloudIp;
} else {
try {
result.ip = (await checkDNS()).cloudIp;
logger.debug('DNS_CHECK_RESULT', await checkDNS());
store.dispatch(setDNSCheck({ cloudIp: result.ip, ttl: FIVE_DAYS_SECS, error: null }));
} catch (error: unknown) {
logger.warn('Failed to fetch DNS, but Minigraph is connected - continuing');
result.ip = `ERROR: ${error instanceof Error ? error.message : 'Unknown Error'}`;
// Don't set an error since we're actually connected to the cloud
store.dispatch(setDNSCheck({ cloudIp: result.ip, ttl: ONE_DAY_SECS, error: null }));
}
}
return result;
};
export const checkCloud = async (): Promise<CloudResponse> => {
logger.trace('Cloud endpoint: Checking mothership');
try {
const config = getters.config();
const apiVersion = API_VERSION;
const apiKey = config.remote.apikey;
const graphqlStatus = getters.minigraph().status;
const result = { status: 'ok', error: null, ip: 'NO_IP_FOUND' };
// If minigraph is connected, skip the follow cloud checks
if (graphqlStatus === MinigraphStatus.CONNECTED) {
return await fastCloudCheck();
}
// Check GraphQL Conneciton State, if it's broken, run these checks
if (!apiKey) throw new Error('API key is missing');
const oldCheckResult = getCloudCache();
if (oldCheckResult) {
logger.trace('Using cached result for cloud check', oldCheckResult);
return oldCheckResult;
}
// Check DNS
result.ip = (await checkDNS()).cloudIp;
// Check if we can reach mothership
await checkCanReachMothership(apiVersion, apiKey);
// Check auth, rate limiting, etc.
await checkMothershipAuthentication(apiVersion, apiKey);
// Cache for 10 minutes
store.dispatch(setCloudCheck(result));
return result;
} catch (error: unknown) {
if (!(error instanceof Error)) throw new Error(`Unknown Error "${error as string}"`);
return { status: 'error', error: error.message };
}
};

View File

@@ -1,8 +1,3 @@
/*!
* Copyright 2022 Lime Technology Inc. All rights reserved.
* Written by: Alexis Tyler
*/
import { MOTHERSHIP_GRAPHQL_LINK } from '@app/consts';
import { store } from '@app/store';
import { getDnsCache } from '@app/store/getters';

View File

@@ -0,0 +1,14 @@
export type Cloud = {
error: string | null;
apiKey: { valid: true; error: null } | { valid: false; error: string };
minigraphql: {
status: 'connected' | 'disconnected';
};
cloud: { status: 'ok'; error: null; ip: string } | { status: 'error'; error: string };
allowedOrigins: string[];
};
export const createResponse = (cloud: Omit<Cloud, 'error'>): Cloud => ({
...cloud,
error: cloud.apiKey.error ?? cloud.cloud.error,
});

View File

@@ -22,7 +22,8 @@ import { fileExists } from '@app/core/utils/files/file-exists';
import { encode as encodeIni } from 'ini';
import { v7 as uuidv7 } from 'uuid';
import { CHOKIDAR_USEPOLLING } from '@app/environment';
import { emptyDir, statSync } from 'fs-extra';
import { emptyDir } from 'fs-extra';
import { statSync } from 'fs';
import { execa } from 'execa';
import { AppError } from '@app/core/errors/app-error';
import { SortFn } from '@app/unraid-api/types/util';