Data Protection & Privacy

Data encryption, privacy compliance, and security measures for protecting sensitive information in Smart Shelf.

Data Protection & Privacy

Comprehensive data protection and privacy implementation for Smart Shelf, covering encryption strategies, privacy compliance (GDPR), and security measures for sensitive information.

Data Classification

Data Sensitivity Levels

// lib/security/data-classification.ts
export enum DataSensitivity {
  PUBLIC = 'public',           // Product catalogs, public information
  INTERNAL = 'internal',       // Business operations data
  CONFIDENTIAL = 'confidential', // Financial data, pricing
  RESTRICTED = 'restricted',   // Personal data, authentication
}

export const DATA_CLASSIFICATION = {
  // User data
  'user_profiles.email': DataSensitivity.RESTRICTED,
  'user_profiles.full_name': DataSensitivity.RESTRICTED,
  'user_profiles.phone': DataSensitivity.RESTRICTED,
  
  // Product data
  'products.name': DataSensitivity.PUBLIC,
  'products.description': DataSensitivity.PUBLIC,
  'products.cost_price': DataSensitivity.CONFIDENTIAL,
  'products.selling_price': DataSensitivity.INTERNAL,
  
  // Financial data
  'orders.total_amount': DataSensitivity.CONFIDENTIAL,
  'purchase_orders.total_cost': DataSensitivity.CONFIDENTIAL,
  
  // Operational data
  'inventory.quantity_on_hand': DataSensitivity.INTERNAL,
  'stock_movements.*': DataSensitivity.INTERNAL,
} as const;

export function getDataSensitivity(field: string): DataSensitivity {
  return DATA_CLASSIFICATION[field as keyof typeof DATA_CLASSIFICATION] || DataSensitivity.INTERNAL;
}

Encryption Implementation

Field-Level Encryption

// lib/security/encryption.ts
import crypto from 'crypto';

export class FieldEncryption {
  private static readonly ALGORITHM = 'aes-256-gcm';
  private static readonly KEY_LENGTH = 32;
  private static readonly IV_LENGTH = 16;
  private static readonly TAG_LENGTH = 16;
  
  private static getEncryptionKey(): Buffer {
    const key = process.env.ENCRYPTION_KEY;
    if (!key) {
      throw new Error('Encryption key not configured');
    }
    return Buffer.from(key, 'hex');
  }
  
  static encrypt(plaintext: string): string {
    try {
      const key = this.getEncryptionKey();
      const iv = crypto.randomBytes(this.IV_LENGTH);
      const cipher = crypto.createCipher(this.ALGORITHM, key);
      cipher.setAAD(Buffer.from('smart-shelf', 'utf8'));
      
      let encrypted = cipher.update(plaintext, 'utf8', 'hex');
      encrypted += cipher.final('hex');
      
      const authTag = cipher.getAuthTag();
      
      // Combine IV + encrypted data + auth tag
      return iv.toString('hex') + ':' + encrypted + ':' + authTag.toString('hex');
    } catch (error) {
      throw new Error('Encryption failed');
    }
  }
  
  static decrypt(encryptedData: string): string {
    try {
      const parts = encryptedData.split(':');
      if (parts.length !== 3) {
        throw new Error('Invalid encrypted data format');
      }
      
      const key = this.getEncryptionKey();
      const iv = Buffer.from(parts[0], 'hex');
      const encrypted = parts[1];
      const authTag = Buffer.from(parts[2], 'hex');
      
      const decipher = crypto.createDecipher(this.ALGORITHM, key);
      decipher.setAAD(Buffer.from('smart-shelf', 'utf8'));
      decipher.setAuthTag(authTag);
      
      let decrypted = decipher.update(encrypted, 'hex', 'utf8');
      decrypted += decipher.final('utf8');
      
      return decrypted;
    } catch (error) {
      throw new Error('Decryption failed');
    }
  }
}

// Usage in models
export class SecureUser {
  id: string;
  email: string; // Encrypted
  full_name: string; // Encrypted
  role: string;
  
  static fromDatabase(data: any): SecureUser {
    return {
      id: data.id,
      email: FieldEncryption.decrypt(data.encrypted_email),
      full_name: FieldEncryption.decrypt(data.encrypted_full_name),
      role: data.role,
    };
  }
  
  toDatabase(): any {
    return {
      id: this.id,
      encrypted_email: FieldEncryption.encrypt(this.email),
      encrypted_full_name: FieldEncryption.encrypt(this.full_name),
      role: this.role,
    };
  }
}

Database Encryption

-- Enable pgcrypto extension for database-level encryption
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- Function to encrypt sensitive data
CREATE OR REPLACE FUNCTION encrypt_pii(data TEXT)
RETURNS TEXT AS $$
BEGIN
  RETURN encode(
    encrypt(
      data::bytea,
      current_setting('app.encryption_key')::bytea,
      'aes'
    ),
    'base64'
  );
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Function to decrypt sensitive data
CREATE OR REPLACE FUNCTION decrypt_pii(encrypted_data TEXT)
RETURNS TEXT AS $$
BEGIN
  RETURN convert_from(
    decrypt(
      decode(encrypted_data, 'base64'),
      current_setting('app.encryption_key')::bytea,
      'aes'
    ),
    'UTF8'
  );
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Encrypted user profiles table
CREATE TABLE encrypted_user_profiles (
  id UUID PRIMARY KEY REFERENCES auth.users(id),
  encrypted_email TEXT NOT NULL,
  encrypted_full_name TEXT NOT NULL,
  encrypted_phone TEXT,
  role user_role NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

Privacy Compliance (GDPR)

Data Subject Rights

// lib/privacy/gdpr.ts
export enum DataSubjectRight {
  ACCESS = 'access',           // Right to access personal data
  RECTIFICATION = 'rectification', // Right to correct data
  ERASURE = 'erasure',         // Right to be forgotten
  PORTABILITY = 'portability', // Right to data portability
  RESTRICTION = 'restriction', // Right to restrict processing
  OBJECTION = 'objection',     // Right to object to processing
}

export interface DataProcessingRecord {
  id: string;
  user_id: string;
  processing_purpose: string;
  legal_basis: 'consent' | 'contract' | 'legal_obligation' | 'vital_interests' | 'public_task' | 'legitimate_interests';
  data_categories: string[];
  retention_period: string;
  consent_given: boolean;
  consent_date?: Date;
  created_at: Date;
}

export class GDPRCompliance {
  static async getPersonalData(userId: string): Promise<any> {
    const supabase = createServerComponentClient({ cookies });
    
    // Collect all personal data for the user
    const personalData = {
      profile: await this.getUserProfile(userId),
      activities: await this.getUserActivities(userId),
      preferences: await this.getUserPreferences(userId),
    };
    
    // Log access request
    await this.logDataAccess(userId, 'personal_data_export');
    
    return personalData;
  }
  
  static async deletePersonalData(userId: string, reason: string): Promise<void> {
    const supabase = createServerComponentClient({ cookies });
    
    try {
      // Start transaction
      await supabase.rpc('begin_transaction');
      
      // Anonymize instead of delete to maintain referential integrity
      await this.anonymizeUserData(userId);
      
      // Log deletion
      await this.logDataDeletion(userId, reason);
      
      // Commit transaction
      await supabase.rpc('commit_transaction');
      
    } catch (error) {
      await supabase.rpc('rollback_transaction');
      throw error;
    }
  }
  
  private static async anonymizeUserData(userId: string): Promise<void> {
    const supabase = createServerComponentClient({ cookies });
    
    // Anonymize user profile
    await supabase
      .from('user_profiles')
      .update({
        encrypted_email: FieldEncryption.encrypt('anonymized@example.com'),
        encrypted_full_name: FieldEncryption.encrypt('Anonymized User'),
        encrypted_phone: null,
        is_active: false,
        anonymized_at: new Date().toISOString(),
      })
      .eq('id', userId);
    
    // Remove personal identifiers from audit logs
    await supabase
      .from('audit_log')
      .update({
        old_values: {},
        new_values: {},
        anonymized: true,
      })
      .eq('changed_by', userId);
  }
  
  static async recordConsent(
    userId: string,
    purpose: string,
    legalBasis: string,
    dataCategories: string[]
  ): Promise<void> {
    const supabase = createServerComponentClient({ cookies });
    
    await supabase
      .from('data_processing_records')
      .insert({
        user_id: userId,
        processing_purpose: purpose,
        legal_basis: legalBasis,
        data_categories: dataCategories,
        consent_given: true,
        consent_date: new Date().toISOString(),
      });
  }
  
  static async withdrawConsent(userId: string, purpose: string): Promise<void> {
    const supabase = createServerComponentClient({ cookies });
    
    await supabase
      .from('data_processing_records')
      .update({
        consent_given: false,
        consent_withdrawn_at: new Date().toISOString(),
      })
      .eq('user_id', userId)
      .eq('processing_purpose', purpose);
  }
}

Data Retention Policies

// lib/privacy/retention.ts
export interface RetentionPolicy {
  dataType: string;
  retentionPeriod: number; // in days
  deletionMethod: 'hard_delete' | 'soft_delete' | 'anonymize';
  legalBasis: string;
}

export const RETENTION_POLICIES: RetentionPolicy[] = [
  {
    dataType: 'user_activity_logs',
    retentionPeriod: 365,
    deletionMethod: 'hard_delete',
    legalBasis: 'Security monitoring',
  },
  {
    dataType: 'financial_records',
    retentionPeriod: 2555, // 7 years
    deletionMethod: 'anonymize',
    legalBasis: 'Legal obligation',
  },
  {
    dataType: 'marketing_preferences',
    retentionPeriod: 1095, // 3 years
    deletionMethod: 'hard_delete',
    legalBasis: 'Consent',
  },
  {
    dataType: 'audit_logs',
    retentionPeriod: 2190, // 6 years
    deletionMethod: 'anonymize',
    legalBasis: 'Legal obligation',
  },
];

export class DataRetentionManager {
  static async enforceRetentionPolicies(): Promise<void> {
    for (const policy of RETENTION_POLICIES) {
      await this.enforcePolicy(policy);
    }
  }
  
  private static async enforcePolicy(policy: RetentionPolicy): Promise<void> {
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - policy.retentionPeriod);
    
    switch (policy.deletionMethod) {
      case 'hard_delete':
        await this.hardDelete(policy.dataType, cutoffDate);
        break;
      case 'soft_delete':
        await this.softDelete(policy.dataType, cutoffDate);
        break;
      case 'anonymize':
        await this.anonymizeData(policy.dataType, cutoffDate);
        break;
    }
  }
  
  private static async hardDelete(dataType: string, cutoffDate: Date): Promise<void> {
    const supabase = createServerComponentClient({ cookies });
    
    const { error } = await supabase
      .from(dataType)
      .delete()
      .lt('created_at', cutoffDate.toISOString());
    
    if (error) {
      console.error(`Failed to delete expired ${dataType}:`, error);
    }
  }
  
  private static async anonymizeData(dataType: string, cutoffDate: Date): Promise<void> {
    const supabase = createServerComponentClient({ cookies });
    
    const { error } = await supabase
      .from(dataType)
      .update({ anonymized: true, anonymized_at: new Date().toISOString() })
      .lt('created_at', cutoffDate.toISOString())
      .is('anonymized', null);
    
    if (error) {
      console.error(`Failed to anonymize expired ${dataType}:`, error);
    }
  }
}

Data Masking and Sanitization

Data Masking Utilities

// lib/security/data-masking.ts
export class DataMasking {
  static maskEmail(email: string): string {
    const [username, domain] = email.split('@');
    const maskedUsername = username.substring(0, 2) + '*'.repeat(username.length - 2);
    return `${maskedUsername}@${domain}`;
  }
  
  static maskPhone(phone: string): string {
    if (phone.length < 4) return phone;
    return '*'.repeat(phone.length - 4) + phone.slice(-4);
  }
  
  static maskCreditCard(cardNumber: string): string {
    if (cardNumber.length < 4) return cardNumber;
    return '*'.repeat(cardNumber.length - 4) + cardNumber.slice(-4);
  }
  
  static maskBankAccount(accountNumber: string): string {
    if (accountNumber.length < 4) return accountNumber;
    return '*'.repeat(accountNumber.length - 4) + accountNumber.slice(-4);
  }
  
  static sanitizeForLogging(data: any): any {
    const sensitiveFields = ['password', 'token', 'secret', 'key', 'email', 'phone'];
    
    if (typeof data !== 'object' || data === null) {
      return data;
    }
    
    const sanitized = { ...data };
    
    for (const key in sanitized) {
      const isSecretField = sensitiveFields.some(field => 
        key.toLowerCase().includes(field)
      );
      
      if (isSecretField) {
        sanitized[key] = '[REDACTED]';
      } else if (typeof sanitized[key] === 'object') {
        sanitized[key] = this.sanitizeForLogging(sanitized[key]);
      }
    }
    
    return sanitized;
  }
}

// Usage in API responses
export function sanitizeUserForResponse(user: any): any {
  return {
    id: user.id,
    email: DataMasking.maskEmail(user.email),
    full_name: user.full_name,
    role: user.role,
    // Remove sensitive fields
    created_at: user.created_at,
  };
}

Secure Data Storage

Database Security Functions

-- Function to securely store sensitive data
CREATE OR REPLACE FUNCTION store_sensitive_data(
  table_name TEXT,
  record_id UUID,
  field_name TEXT,
  sensitive_value TEXT
)
RETURNS VOID AS $$
DECLARE
  encrypted_value TEXT;
BEGIN
  -- Encrypt the sensitive value
  encrypted_value := encrypt_pii(sensitive_value);
  
  -- Store in secure vault table
  INSERT INTO secure_data_vault (
    table_name,
    record_id,
    field_name,
    encrypted_value,
    created_at
  ) VALUES (
    table_name,
    record_id,
    field_name,
    encrypted_value,
    NOW()
  )
  ON CONFLICT (table_name, record_id, field_name) 
  DO UPDATE SET 
    encrypted_value = EXCLUDED.encrypted_value,
    updated_at = NOW();
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Function to retrieve sensitive data
CREATE OR REPLACE FUNCTION get_sensitive_data(
  table_name TEXT,
  record_id UUID,
  field_name TEXT
)
RETURNS TEXT AS $$
DECLARE
  encrypted_value TEXT;
BEGIN
  SELECT sdv.encrypted_value INTO encrypted_value
  FROM secure_data_vault sdv
  WHERE sdv.table_name = get_sensitive_data.table_name
    AND sdv.record_id = get_sensitive_data.record_id
    AND sdv.field_name = get_sensitive_data.field_name;
  
  IF encrypted_value IS NULL THEN
    RETURN NULL;
  END IF;
  
  RETURN decrypt_pii(encrypted_value);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Secure data vault table
CREATE TABLE secure_data_vault (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  table_name TEXT NOT NULL,
  record_id UUID NOT NULL,
  field_name TEXT NOT NULL,
  encrypted_value TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(table_name, record_id, field_name)
);

Privacy by Design Implementation

Privacy Impact Assessment

// lib/privacy/impact-assessment.ts
export interface PrivacyImpactAssessment {
  feature: string;
  dataTypes: string[];
  processingPurpose: string;
  legalBasis: string;
  riskLevel: 'low' | 'medium' | 'high';
  mitigationMeasures: string[];
  approvedBy: string;
  approvedAt: Date;
}

export class PrivacyByDesign {
  static async conductPIA(feature: string): Promise<PrivacyImpactAssessment> {
    const assessment: PrivacyImpactAssessment = {
      feature,
      dataTypes: this.identifyDataTypes(feature),
      processingPurpose: this.getProcessingPurpose(feature),
      legalBasis: this.determineLegalBasis(feature),
      riskLevel: this.assessRiskLevel(feature),
      mitigationMeasures: this.getMitigationMeasures(feature),
      approvedBy: 'Data Protection Officer',
      approvedAt: new Date(),
    };
    
    // Store assessment
    await this.storePIA(assessment);
    
    return assessment;
  }
  
  private static assessRiskLevel(feature: string): 'low' | 'medium' | 'high' {
    const highRiskFeatures = ['user_tracking', 'financial_data', 'biometric_data'];
    const mediumRiskFeatures = ['user_preferences', 'activity_logs'];
    
    if (highRiskFeatures.some(risk => feature.includes(risk))) {
      return 'high';
    }
    
    if (mediumRiskFeatures.some(risk => feature.includes(risk))) {
      return 'medium';
    }
    
    return 'low';
  }
}

This comprehensive data protection and privacy framework ensures Smart Shelf complies with privacy regulations while maintaining security and usability.