| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- /**
- * Platform Detection Utility
- *
- * Smart platform identification for accounts based on credential patterns,
- * key formats, and other distinguishing characteristics.
- */
- import { Platform, IPlatformDetector, Credentials } from '@/types/credential';
- /**
- * Pacifica platform detector
- * Detects Ed25519 credentials with specific patterns
- */
- export class PacificaDetector implements IPlatformDetector {
- readonly confidence = 0.9;
- detect(credentials: any): Platform | null {
- if (!credentials || typeof credentials !== 'object') {
- return null;
- }
- // Check for Ed25519 signature type
- if (credentials.type === 'ed25519') {
- return Platform.PACIFICA;
- }
- // Check for 64-character hex private key (Ed25519 format)
- if (credentials.privateKey && typeof credentials.privateKey === 'string') {
- const privateKey = credentials.privateKey.toLowerCase();
- // Ed25519 private key: 64 hex characters (32 bytes)
- if (/^[0-9a-f]{64}$/.test(privateKey)) {
- return Platform.PACIFICA;
- }
- }
- // Check for base58 public key pattern (common in Pacifica)
- if (credentials.publicKey && typeof credentials.publicKey === 'string') {
- const publicKey = credentials.publicKey;
- // Base58 encoded keys are typically 32-44 characters
- if (/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(publicKey) && !publicKey.startsWith('0x')) {
- return Platform.PACIFICA;
- }
- }
- return null;
- }
- }
- /**
- * Aster platform detector
- * Detects EIP-191 (Ethereum-style) credentials
- */
- export class AsterDetector implements IPlatformDetector {
- readonly confidence = 0.85;
- detect(credentials: any): Platform | null {
- if (!credentials || typeof credentials !== 'object') {
- return null;
- }
- // Check for EIP-191 signature type
- if (credentials.type === 'eip191') {
- return Platform.ASTER;
- }
- // Check for 0x-prefixed private key (Ethereum format)
- if (credentials.privateKey && typeof credentials.privateKey === 'string') {
- const privateKey = credentials.privateKey.toLowerCase();
- // Ethereum private key: 0x + 64 hex characters
- if (/^0x[0-9a-f]{64}$/.test(privateKey)) {
- return Platform.ASTER;
- }
- }
- // Check for Ethereum address pattern
- if (credentials.address && typeof credentials.address === 'string') {
- const address = credentials.address.toLowerCase();
- // Ethereum address: 0x + 40 hex characters
- if (/^0x[0-9a-f]{40}$/.test(address)) {
- return Platform.ASTER;
- }
- }
- // Check for public key in Ethereum format
- if (credentials.publicKey && typeof credentials.publicKey === 'string') {
- const publicKey = credentials.publicKey.toLowerCase();
- // Ethereum public key: 0x + 128 hex characters (uncompressed)
- if (/^0x[0-9a-f]{128}$/.test(publicKey)) {
- return Platform.ASTER;
- }
- }
- return null;
- }
- }
- /**
- * Binance platform detector
- * Detects HMAC-SHA256 API key/secret credentials
- */
- export class BinanceDetector implements IPlatformDetector {
- readonly confidence = 0.95;
- detect(credentials: any): Platform | null {
- if (!credentials || typeof credentials !== 'object') {
- return null;
- }
- // Check for HMAC signature type
- if (credentials.type === 'hmac') {
- return Platform.BINANCE;
- }
- // Check for API key/secret pattern
- const hasApiKey = credentials.apiKey && typeof credentials.apiKey === 'string';
- const hasSecretKey = credentials.secretKey && typeof credentials.secretKey === 'string';
- if (hasApiKey && hasSecretKey) {
- const apiKey = credentials.apiKey;
- const secretKey = credentials.secretKey;
- // Binance API keys are typically 64 characters, alphanumeric
- const binanceApiKeyPattern = /^[A-Za-z0-9]{64}$/;
- // Binance secret keys are typically 64 characters, alphanumeric
- const binanceSecretKeyPattern = /^[A-Za-z0-9]{64}$/;
- if (binanceApiKeyPattern.test(apiKey) && binanceSecretKeyPattern.test(secretKey)) {
- return Platform.BINANCE;
- }
- // Alternative: any API key/secret combination for HMAC
- if (apiKey.length >= 16 && secretKey.length >= 16) {
- return Platform.BINANCE;
- }
- }
- return null;
- }
- }
- /**
- * Main platform detector that uses multiple detectors
- */
- export class PlatformDetector {
- private detectors: IPlatformDetector[];
- constructor() {
- this.detectors = [
- new BinanceDetector(), // Highest confidence first
- new PacificaDetector(),
- new AsterDetector()
- ];
- }
- /**
- * Detect platform for given credentials
- * @param credentials Credential object to analyze
- * @returns Detected platform or null if cannot determine
- */
- detectPlatform(credentials: any): Platform | null {
- if (!credentials) {
- return null;
- }
- // Try each detector in order of confidence
- for (const detector of this.detectors) {
- const platform = detector.detect(credentials);
- if (platform) {
- return platform;
- }
- }
- return null;
- }
- /**
- * Get detection results from all detectors
- * @param credentials Credential object to analyze
- * @returns Array of detection results with confidence scores
- */
- getAllDetectionResults(credentials: any): Array<{
- platform: Platform | null;
- confidence: number;
- detector: string;
- }> {
- const results = [];
- for (const detector of this.detectors) {
- const platform = detector.detect(credentials);
- results.push({
- platform,
- confidence: detector.confidence,
- detector: detector.constructor.name
- });
- }
- return results;
- }
- /**
- * Validate that credentials match the specified platform
- * @param credentials Credential object
- * @param expectedPlatform Expected platform
- * @returns True if credentials match the platform
- */
- validatePlatformMatch(credentials: any, expectedPlatform: Platform): boolean {
- const detectedPlatform = this.detectPlatform(credentials);
- return detectedPlatform === expectedPlatform;
- }
- /**
- * Get suggested platforms for ambiguous credentials
- * @param credentials Credential object
- * @returns Array of possible platforms with confidence scores
- */
- getSuggestedPlatforms(credentials: any): Array<{
- platform: Platform;
- confidence: number;
- reason: string;
- }> {
- const suggestions = [];
- const results = this.getAllDetectionResults(credentials);
- for (const result of results) {
- if (result.platform) {
- suggestions.push({
- platform: result.platform,
- confidence: result.confidence,
- reason: `Detected by ${result.detector}`
- });
- }
- }
- // Sort by confidence (highest first)
- return suggestions.sort((a, b) => b.confidence - a.confidence);
- }
- /**
- * Add custom detector
- * @param detector Custom platform detector
- */
- addDetector(detector: IPlatformDetector): void {
- this.detectors.push(detector);
- // Re-sort by confidence (highest first)
- this.detectors.sort((a, b) => b.confidence - a.confidence);
- }
- /**
- * Remove detector by class name
- * @param detectorName Name of detector class to remove
- */
- removeDetector(detectorName: string): void {
- this.detectors = this.detectors.filter(
- detector => detector.constructor.name !== detectorName
- );
- }
- /**
- * Check if credentials are valid for any supported platform
- * @param credentials Credential object
- * @returns True if credentials are valid for at least one platform
- */
- isValidCredentials(credentials: any): boolean {
- return this.detectPlatform(credentials) !== null;
- }
- /**
- * Generate credential validation report
- * @param credentials Credential object
- * @returns Detailed validation report
- */
- generateValidationReport(credentials: any): {
- isValid: boolean;
- detectedPlatform: Platform | null;
- allResults: Array<{
- platform: Platform | null;
- confidence: number;
- detector: string;
- }>;
- suggestions: Array<{
- platform: Platform;
- confidence: number;
- reason: string;
- }>;
- issues: string[];
- } {
- const detectedPlatform = this.detectPlatform(credentials);
- const allResults = this.getAllDetectionResults(credentials);
- const suggestions = this.getSuggestedPlatforms(credentials);
- const issues = [];
- // Check for common issues
- if (!credentials) {
- issues.push('No credentials provided');
- } else if (typeof credentials !== 'object') {
- issues.push('Credentials must be an object');
- } else {
- if (!detectedPlatform) {
- issues.push('Could not detect platform from credentials');
- }
- if (!credentials.type) {
- issues.push('Missing credential type');
- }
- // Platform-specific validation
- if (credentials.type === 'ed25519' && !credentials.privateKey) {
- issues.push('Ed25519 credentials missing privateKey');
- }
- if (credentials.type === 'eip191' && !credentials.privateKey) {
- issues.push('EIP-191 credentials missing privateKey');
- }
- if (credentials.type === 'hmac' && (!credentials.apiKey || !credentials.secretKey)) {
- issues.push('HMAC credentials missing apiKey or secretKey');
- }
- }
- return {
- isValid: detectedPlatform !== null && issues.length === 0,
- detectedPlatform,
- allResults,
- suggestions,
- issues
- };
- }
- }
|