437 lines
9.7 KiB
TypeScript
437 lines
9.7 KiB
TypeScript
/**
|
|
* @file signature.ts
|
|
* @description Signature data structures and types
|
|
* Supports drawn, typed, click, digital, qualified, and biometric signatures
|
|
*/
|
|
|
|
import type {
|
|
TSignatureType,
|
|
TSignatureLegalLevel,
|
|
TSignatureStatus,
|
|
TSignatureAuditAction,
|
|
THashAlgorithm,
|
|
TSignatureAlgorithm,
|
|
} from './types.js';
|
|
|
|
// ============================================================================
|
|
// SIGNATURE DATA STRUCTURES (Discriminated Union)
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Base signature data common to all types
|
|
*/
|
|
export interface ISignatureDataBase {
|
|
id: string;
|
|
schemaVersion: '1.0.0';
|
|
capturedAt: number;
|
|
}
|
|
|
|
/**
|
|
* Individual stroke point from signature_pad
|
|
*/
|
|
export interface ISignatureStrokePoint {
|
|
x: number;
|
|
y: number;
|
|
pressure: number;
|
|
time: number;
|
|
}
|
|
|
|
/**
|
|
* Drawn signature data (canvas-based)
|
|
* Compatible with signature_pad library output
|
|
*/
|
|
export interface ISignatureDataDrawn extends ISignatureDataBase {
|
|
type: 'drawn';
|
|
strokeData: ISignatureStrokePoint[][];
|
|
svg: string;
|
|
pngBase64?: string;
|
|
canvasDimensions: {
|
|
width: number;
|
|
height: number;
|
|
devicePixelRatio: number;
|
|
};
|
|
drawingMetrics?: {
|
|
totalStrokes: number;
|
|
totalPoints: number;
|
|
averageVelocity: number;
|
|
drawingDurationMs: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Typed signature data
|
|
*/
|
|
export interface ISignatureDataTyped extends ISignatureDataBase {
|
|
type: 'typed';
|
|
text: string;
|
|
fontFamily: string;
|
|
fontSize: number;
|
|
svg: string;
|
|
pngBase64?: string;
|
|
}
|
|
|
|
/**
|
|
* Click-to-sign acknowledgment
|
|
*/
|
|
export interface ISignatureDataClick extends ISignatureDataBase {
|
|
type: 'click';
|
|
acknowledgmentText: string;
|
|
acknowledged: boolean;
|
|
fullNameEntered?: string;
|
|
jobTitle?: string;
|
|
}
|
|
|
|
/**
|
|
* Certificate information for digital signatures
|
|
*/
|
|
export interface ICertificateInfo {
|
|
certificatePem: string;
|
|
serialNumber: string;
|
|
issuer: string;
|
|
subject: string;
|
|
validity: {
|
|
notBefore: number;
|
|
notAfter: number;
|
|
};
|
|
fingerprint: string;
|
|
}
|
|
|
|
/**
|
|
* Digital certificate-based signature (X.509/PKI)
|
|
*/
|
|
export interface ISignatureDataDigital extends ISignatureDataBase {
|
|
type: 'digital';
|
|
certificate: ICertificateInfo;
|
|
signatureValue: string;
|
|
signatureAlgorithm: TSignatureAlgorithm;
|
|
contentHash: string;
|
|
hashAlgorithm: THashAlgorithm;
|
|
}
|
|
|
|
/**
|
|
* Qualified Trust Service Provider information
|
|
*/
|
|
export interface IQtspInfo {
|
|
name: string;
|
|
providerId: string;
|
|
serviceId: string;
|
|
country: string;
|
|
}
|
|
|
|
/**
|
|
* Signature creation device information
|
|
*/
|
|
export interface ISignatureCreationDevice {
|
|
type: 'local' | 'remote';
|
|
deviceId?: string;
|
|
certification?: string;
|
|
}
|
|
|
|
/**
|
|
* Qualified Electronic Signature (eIDAS QES)
|
|
*/
|
|
export interface ISignatureDataQualified extends ISignatureDataBase {
|
|
type: 'qualified';
|
|
digitalSignature: Omit<ISignatureDataDigital, 'type' | 'id' | 'schemaVersion' | 'capturedAt'>;
|
|
qtsp: IQtspInfo;
|
|
trustedListReference?: string;
|
|
signatureCreationDevice?: ISignatureCreationDevice;
|
|
}
|
|
|
|
/**
|
|
* Biometric signature data (extensible for future)
|
|
*/
|
|
export interface ISignatureDataBiometric extends ISignatureDataBase {
|
|
type: 'biometric';
|
|
biometricType: 'fingerprint' | 'facial' | 'voice' | 'iris';
|
|
templateReference: string;
|
|
confidenceScore: number;
|
|
provider: string;
|
|
}
|
|
|
|
/**
|
|
* Union type of all signature data types
|
|
*/
|
|
export type TSignatureData =
|
|
| ISignatureDataDrawn
|
|
| ISignatureDataTyped
|
|
| ISignatureDataClick
|
|
| ISignatureDataDigital
|
|
| ISignatureDataQualified
|
|
| ISignatureDataBiometric;
|
|
|
|
// ============================================================================
|
|
// SIGNATURE METADATA
|
|
// ============================================================================
|
|
|
|
/**
|
|
* IP geolocation information
|
|
*/
|
|
export interface IIpGeolocation {
|
|
country: string;
|
|
countryCode: string;
|
|
region?: string;
|
|
city?: string;
|
|
}
|
|
|
|
/**
|
|
* Device fingerprint for fraud detection
|
|
*/
|
|
export interface IDeviceFingerprint {
|
|
hash: string;
|
|
components: {
|
|
screenResolution?: string;
|
|
timezone?: string;
|
|
language?: string;
|
|
platform?: string;
|
|
colorDepth?: number;
|
|
touchSupport?: boolean;
|
|
canvasFingerprint?: string;
|
|
webglFingerprint?: string;
|
|
};
|
|
confidence: number;
|
|
}
|
|
|
|
/**
|
|
* Session information
|
|
*/
|
|
export interface ISigningSession {
|
|
sessionId: string;
|
|
sessionStarted: number;
|
|
pageViews: number;
|
|
documentsViewed: string[];
|
|
}
|
|
|
|
/**
|
|
* Comprehensive signature metadata capturing context
|
|
*/
|
|
export interface ISignatureMetadata {
|
|
timestamps: {
|
|
clientCaptured: number;
|
|
serverReceived?: number;
|
|
blockchainTimestamped?: number;
|
|
tsaTimestamped?: number;
|
|
};
|
|
geolocation?: {
|
|
latitude: number;
|
|
longitude: number;
|
|
accuracy: number;
|
|
altitude?: number;
|
|
timestamp: number;
|
|
source: 'gps' | 'network' | 'ip-based';
|
|
};
|
|
network: {
|
|
ipAddress: string;
|
|
ipGeolocation?: IIpGeolocation;
|
|
userAgent: string;
|
|
};
|
|
deviceFingerprint?: IDeviceFingerprint;
|
|
session?: ISigningSession;
|
|
}
|
|
|
|
// ============================================================================
|
|
// CONSENT AND VERIFICATION
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Legal consent record
|
|
*/
|
|
export interface IConsent {
|
|
type: 'terms_accepted' | 'electronic_signature' | 'data_processing' | 'custom';
|
|
text: string;
|
|
accepted: boolean;
|
|
timestamp?: number;
|
|
}
|
|
|
|
/**
|
|
* Signature audit trail entry
|
|
*/
|
|
export interface ISignatureAuditEntry {
|
|
timestamp: number;
|
|
action: TSignatureAuditAction;
|
|
actor: {
|
|
type: 'user' | 'system' | 'service';
|
|
id: string;
|
|
name?: string;
|
|
};
|
|
details: Record<string, unknown>;
|
|
ipAddress?: string;
|
|
}
|
|
|
|
// ============================================================================
|
|
// COMPLETE SIGNATURE OBJECT
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Forward declaration for identity verification (defined in identity.ts)
|
|
*/
|
|
export interface IIdentityVerificationResultRef {
|
|
id: string;
|
|
status: string;
|
|
confidence: string;
|
|
}
|
|
|
|
/**
|
|
* Forward declaration for legal compliance proof (defined in legal.ts)
|
|
*/
|
|
export interface ILegalComplianceProofRef {
|
|
id: string;
|
|
eidasLevel?: TSignatureLegalLevel;
|
|
}
|
|
|
|
/**
|
|
* Complete signature with data, metadata, and verification status
|
|
*/
|
|
export interface ISignature {
|
|
id: string;
|
|
schemaVersion: '1.0.0';
|
|
signatureType: TSignatureType;
|
|
legalLevel: TSignatureLegalLevel;
|
|
data: TSignatureData;
|
|
metadata: ISignatureMetadata;
|
|
identityVerificationId?: string;
|
|
legalComplianceProofId?: string;
|
|
consents: IConsent[];
|
|
auditTrail: ISignatureAuditEntry[];
|
|
status: TSignatureStatus;
|
|
}
|
|
|
|
// ============================================================================
|
|
// SIGNATURE FIELD PLACEMENT
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Paragraph-based placement
|
|
*/
|
|
export interface IPlacementParagraph {
|
|
paragraphId: string;
|
|
position: 'before' | 'after' | 'inline';
|
|
inlineOffset?: number;
|
|
}
|
|
|
|
/**
|
|
* Page-based placement (PDF coordinates)
|
|
*/
|
|
export interface IPlacementPage {
|
|
pageNumber: number;
|
|
coordinates: {
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Anchor-based placement
|
|
*/
|
|
export interface IPlacementAnchor {
|
|
anchorText: string;
|
|
occurrence: number;
|
|
offset: {
|
|
x: number;
|
|
y: number;
|
|
};
|
|
size: {
|
|
width: number;
|
|
height: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Signature field placement configuration
|
|
*/
|
|
export interface ISignatureFieldPlacement {
|
|
type: 'paragraph' | 'page' | 'anchor' | 'append';
|
|
paragraph?: IPlacementParagraph;
|
|
page?: IPlacementPage;
|
|
anchor?: IPlacementAnchor;
|
|
displayOrder: number;
|
|
}
|
|
|
|
// ============================================================================
|
|
// SIGNATURE FIELD REQUIREMENTS
|
|
// ============================================================================
|
|
|
|
import type { TIdentityVerificationMethod, TVerificationConfidence } from './types.js';
|
|
|
|
/**
|
|
* Requirements for a signature field
|
|
*/
|
|
export interface ISignatureFieldRequirements {
|
|
required: boolean;
|
|
allowedSignatureTypes: TSignatureType[];
|
|
minimumLegalLevel: TSignatureLegalLevel;
|
|
identityVerification: {
|
|
required: boolean;
|
|
allowedMethods?: TIdentityVerificationMethod[];
|
|
minimumConfidence?: TVerificationConfidence;
|
|
};
|
|
timestamping: {
|
|
required: boolean;
|
|
types?: ('tsa' | 'qualified_tsa' | 'blockchain')[];
|
|
};
|
|
deadline?: {
|
|
timestamp?: number;
|
|
relativeSeconds?: number;
|
|
};
|
|
customValidation?: {
|
|
ruleId: string;
|
|
params: Record<string, unknown>;
|
|
}[];
|
|
}
|
|
|
|
// ============================================================================
|
|
// SIGNATURE DEPENDENCIES
|
|
// ============================================================================
|
|
|
|
import type { TFieldDependencyType } from './types.js';
|
|
|
|
/**
|
|
* Defines dependencies between signature fields
|
|
*/
|
|
export interface ISignatureDependency {
|
|
type: TFieldDependencyType;
|
|
dependsOn: string[];
|
|
timeConstraint?: {
|
|
minSecondsAfter?: number;
|
|
maxSecondsAfter?: number;
|
|
};
|
|
}
|
|
|
|
// ============================================================================
|
|
// FACTORY FUNCTIONS
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Create empty signature metadata
|
|
*/
|
|
export function createEmptySignatureMetadata(): ISignatureMetadata {
|
|
return {
|
|
timestamps: {
|
|
clientCaptured: Date.now(),
|
|
},
|
|
network: {
|
|
ipAddress: '',
|
|
userAgent: '',
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create default signature field requirements
|
|
*/
|
|
export function createDefaultSignatureFieldRequirements(): ISignatureFieldRequirements {
|
|
return {
|
|
required: true,
|
|
allowedSignatureTypes: ['drawn', 'typed', 'click'],
|
|
minimumLegalLevel: 'simple',
|
|
identityVerification: {
|
|
required: false,
|
|
},
|
|
timestamping: {
|
|
required: false,
|
|
},
|
|
};
|
|
}
|