Initial commit

This commit is contained in:
root
2025-12-21 09:55:58 -05:00
committed by Sebastian Krupinski
commit 169b7b4c91
57 changed files with 10105 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
/**
* Utility functions for generating unique identifiers
*/
const globalCrypto = typeof globalThis !== "undefined" ? globalThis.crypto : undefined;
export const generateUuid = (): string => {
if (globalCrypto?.randomUUID) {
return globalCrypto.randomUUID();
}
const template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx";
return template.replace(/[xy]/g, char => {
const randomNibble = Math.floor(Math.random() * 16);
const value = char === "x" ? randomNibble : (randomNibble & 0x3) | 0x8;
return value.toString(16);
});
};
export const generateKey = (): string => {
if (globalCrypto?.randomUUID) {
return globalCrypto.randomUUID().replace(/-/g, "");
}
if (globalCrypto?.getRandomValues) {
const [value] = globalCrypto.getRandomValues(new Uint32Array(1));
return value.toString(16);
}
return Math.random().toString(16).slice(2);
};

276
src/utils/serviceHelpers.ts Normal file
View File

@@ -0,0 +1,276 @@
/**
* Helper functions for working with service identity and location types
*/
import type {
ServiceIdentity,
ServiceIdentityNone,
ServiceIdentityBasic,
ServiceIdentityToken,
ServiceIdentityOAuth,
ServiceIdentityCertificate,
ServiceLocation,
ServiceLocationUri,
ServiceLocationSocketSole,
ServiceLocationSocketSplit,
ServiceLocationFile
} from '@/types/service';
// ==================== Identity Helpers ====================
/**
* Create a "None" identity (no authentication)
*/
export function createIdentityNone(): ServiceIdentityNone {
return { type: 'NA' };
}
/**
* Create a Basic Auth identity
*/
export function createIdentityBasic(identity: string, secret: string): ServiceIdentityBasic {
return {
type: 'BA',
identity,
secret
};
}
/**
* Create a Token Auth identity
*/
export function createIdentityToken(token: string): ServiceIdentityToken {
return {
type: 'TA',
token
};
}
/**
* Create an OAuth identity
*/
export function createIdentityOAuth(
accessToken: string,
options?: {
accessScope?: string[];
accessExpiry?: number;
refreshToken?: string;
refreshLocation?: string;
}
): ServiceIdentityOAuth {
return {
type: 'OA',
accessToken,
...options
};
}
/**
* Create a Certificate identity
*/
export function createIdentityCertificate(
certificate: string,
privateKey: string,
passphrase?: string
): ServiceIdentityCertificate {
return {
type: 'CC',
certificate,
privateKey,
...(passphrase && { passphrase })
};
}
// ==================== Location Helpers ====================
/**
* Create a URI-based location
*/
export function createLocationUri(
host: string,
options?: {
scheme?: 'http' | 'https';
port?: number;
path?: string;
verifyPeer?: boolean;
verifyHost?: boolean;
}
): ServiceLocationUri {
return {
type: 'URI',
scheme: options?.scheme || 'https',
host,
port: options?.port || (options?.scheme === 'http' ? 80 : 443),
...(options?.path && { path: options.path }),
verifyPeer: options?.verifyPeer ?? true,
verifyHost: options?.verifyHost ?? true
};
}
/**
* Create a URI location from a full URL string
*/
export function createLocationFromUrl(url: string): ServiceLocationUri {
try {
const parsed = new URL(url);
return {
type: 'URI',
scheme: parsed.protocol.replace(':', '') as 'http' | 'https',
host: parsed.hostname,
port: parsed.port ? parseInt(parsed.port) : (parsed.protocol === 'https:' ? 443 : 80),
path: parsed.pathname,
verifyPeer: true,
verifyHost: true
};
} catch (error) {
throw new Error(`Invalid URL: ${url}`);
}
}
/**
* Create a single socket location (IMAP, SMTP on same server)
*/
export function createLocationSocketSole(
host: string,
port: number,
encryption: 'none' | 'ssl' | 'tls' | 'starttls' = 'ssl',
options?: {
verifyPeer?: boolean;
verifyHost?: boolean;
}
): ServiceLocationSocketSole {
return {
type: 'SOCKET_SOLE',
host,
port,
encryption,
verifyPeer: options?.verifyPeer ?? true,
verifyHost: options?.verifyHost ?? true
};
}
/**
* Create a split socket location (separate IMAP/SMTP servers)
*/
export function createLocationSocketSplit(
config: {
inboundHost: string;
inboundPort: number;
inboundEncryption?: 'none' | 'ssl' | 'tls' | 'starttls';
outboundHost: string;
outboundPort: number;
outboundEncryption?: 'none' | 'ssl' | 'tls' | 'starttls';
inboundVerifyPeer?: boolean;
inboundVerifyHost?: boolean;
outboundVerifyPeer?: boolean;
outboundVerifyHost?: boolean;
}
): ServiceLocationSocketSplit {
return {
type: 'SOCKET_SPLIT',
inboundHost: config.inboundHost,
inboundPort: config.inboundPort,
inboundEncryption: config.inboundEncryption || 'ssl',
outboundHost: config.outboundHost,
outboundPort: config.outboundPort,
outboundEncryption: config.outboundEncryption || 'ssl',
inboundVerifyPeer: config.inboundVerifyPeer ?? true,
inboundVerifyHost: config.inboundVerifyHost ?? true,
outboundVerifyPeer: config.outboundVerifyPeer ?? true,
outboundVerifyHost: config.outboundVerifyHost ?? true
};
}
/**
* Create a file-based location
*/
export function createLocationFile(path: string): ServiceLocationFile {
return {
type: 'FILE',
path
};
}
// ==================== Validation Helpers ====================
/**
* Validate that an identity object is properly formed
*/
export function validateIdentity(identity: ServiceIdentity): boolean {
switch (identity.type) {
case 'NA':
return true;
case 'BA':
return !!(identity as ServiceIdentityBasic).identity &&
!!(identity as ServiceIdentityBasic).secret;
case 'TA':
return !!(identity as ServiceIdentityToken).token;
case 'OA':
return !!(identity as ServiceIdentityOAuth).accessToken;
case 'CC':
return !!(identity as ServiceIdentityCertificate).certificate &&
!!(identity as ServiceIdentityCertificate).privateKey;
default:
return false;
}
}
/**
* Validate that a location object is properly formed
*/
export function validateLocation(location: ServiceLocation): boolean {
switch (location.type) {
case 'URI':
return !!(location as ServiceLocationUri).host &&
!!(location as ServiceLocationUri).port;
case 'SOCKET_SOLE':
return !!(location as ServiceLocationSocketSole).host &&
!!(location as ServiceLocationSocketSole).port;
case 'SOCKET_SPLIT':
const split = location as ServiceLocationSocketSplit;
return !!split.inboundHost && !!split.inboundPort &&
!!split.outboundHost && !!split.outboundPort;
case 'FILE':
return !!(location as ServiceLocationFile).path;
default:
return false;
}
}
// ==================== Type Guards ====================
export function isIdentityNone(identity: ServiceIdentity): identity is ServiceIdentityNone {
return identity.type === 'NA';
}
export function isIdentityBasic(identity: ServiceIdentity): identity is ServiceIdentityBasic {
return identity.type === 'BA';
}
export function isIdentityToken(identity: ServiceIdentity): identity is ServiceIdentityToken {
return identity.type === 'TA';
}
export function isIdentityOAuth(identity: ServiceIdentity): identity is ServiceIdentityOAuth {
return identity.type === 'OA';
}
export function isIdentityCertificate(identity: ServiceIdentity): identity is ServiceIdentityCertificate {
return identity.type === 'CC';
}
export function isLocationUri(location: ServiceLocation): location is ServiceLocationUri {
return location.type === 'URI';
}
export function isLocationSocketSole(location: ServiceLocation): location is ServiceLocationSocketSole {
return location.type === 'SOCKET_SOLE';
}
export function isLocationSocketSplit(location: ServiceLocation): location is ServiceLocationSocketSplit {
return location.type === 'SOCKET_SPLIT';
}
export function isLocationFile(location: ServiceLocation): location is ServiceLocationFile {
return location.type === 'FILE';
}