Refactor VPN proxy client implementation
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
export type DiagnosticSiteStatus = 'available' | 'responded' | 'unavailable';
|
||||
|
||||
export interface DiagnosticIpResult extends Record<string, unknown> {
|
||||
source: string;
|
||||
address: string | null;
|
||||
}
|
||||
|
||||
export interface DiagnosticSiteResult extends Record<string, unknown> {
|
||||
id: string;
|
||||
status: DiagnosticSiteStatus;
|
||||
httpStatus: number | null;
|
||||
latencyMs: number | null;
|
||||
}
|
||||
|
||||
export interface DiagnosticServer extends Record<string, unknown> {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export interface DiagnosticPath extends Record<string, unknown> {
|
||||
available: boolean;
|
||||
internetAvailable: boolean;
|
||||
ipv4: {
|
||||
addresses: string[];
|
||||
sources: DiagnosticIpResult[];
|
||||
};
|
||||
ipv6: string | null;
|
||||
ipv6Source: DiagnosticIpResult | null;
|
||||
sites: DiagnosticSiteResult[];
|
||||
server?: DiagnosticServer | null;
|
||||
}
|
||||
|
||||
export interface ConnectivityResult extends Record<string, unknown> {
|
||||
direct: DiagnosticPath;
|
||||
vpn: DiagnosticPath & { server: DiagnosticServer | null };
|
||||
}
|
||||
|
||||
function record(value: unknown): value is Record<string, unknown> {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function nullableNonnegativeNumber(value: unknown): value is number | null {
|
||||
return value === null || (typeof value === 'number' && Number.isFinite(value) && value >= 0);
|
||||
}
|
||||
|
||||
function validIpResult(value: unknown): value is DiagnosticIpResult {
|
||||
return record(value)
|
||||
&& typeof value.source === 'string'
|
||||
&& value.source.length > 0
|
||||
&& (value.address === null || (typeof value.address === 'string' && value.address.length > 0));
|
||||
}
|
||||
|
||||
function validSiteResult(value: unknown): value is DiagnosticSiteResult {
|
||||
return record(value)
|
||||
&& typeof value.id === 'string'
|
||||
&& value.id.length > 0
|
||||
&& (value.status === 'available' || value.status === 'responded' || value.status === 'unavailable')
|
||||
&& nullableNonnegativeNumber(value.httpStatus)
|
||||
&& nullableNonnegativeNumber(value.latencyMs);
|
||||
}
|
||||
|
||||
function validServer(value: unknown): value is DiagnosticServer | null {
|
||||
return value === null || (record(value)
|
||||
&& typeof value.id === 'string'
|
||||
&& typeof value.label === 'string');
|
||||
}
|
||||
|
||||
function validPath(value: unknown): value is DiagnosticPath {
|
||||
return record(value)
|
||||
&& typeof value.available === 'boolean'
|
||||
&& typeof value.internetAvailable === 'boolean'
|
||||
&& record(value.ipv4)
|
||||
&& Array.isArray(value.ipv4.addresses)
|
||||
&& value.ipv4.addresses.every((address) => typeof address === 'string' && address.length > 0)
|
||||
&& Array.isArray(value.ipv4.sources)
|
||||
&& value.ipv4.sources.every(validIpResult)
|
||||
&& (value.ipv6 === null || (typeof value.ipv6 === 'string' && value.ipv6.length > 0))
|
||||
&& (value.ipv6Source === null || validIpResult(value.ipv6Source))
|
||||
&& Array.isArray(value.sites)
|
||||
&& value.sites.every(validSiteResult);
|
||||
}
|
||||
|
||||
function assertConnectivityResult(value: unknown): asserts value is ConnectivityResult {
|
||||
if (!record(value)
|
||||
|| !validPath(value.direct)
|
||||
|| !validPath(value.vpn)
|
||||
|| !Object.hasOwn(value.vpn, 'server')
|
||||
|| !validServer(value.vpn.server)) {
|
||||
throw new TypeError('Harbor connectivity diagnostics returned an invalid result');
|
||||
}
|
||||
}
|
||||
|
||||
export function parseConnectivityResult(value: unknown): ConnectivityResult {
|
||||
assertConnectivityResult(value);
|
||||
return value;
|
||||
}
|
||||
Reference in New Issue
Block a user