PHP WebShell

Текущая директория: /var/www/bitcardoApp/lib

Просмотр файла: device.php

<?php
// lib/device.php
// Device trust cookie + helpers (keeps your schema/semantics).

/**
 * Create a UUIDv4 (string).
 */
function device_uuid4(): string {
    $d = random_bytes(16);
    $d[6] = chr((ord($d[6]) & 0x0f) | 0x40);
    $d[8] = chr((ord($d[8]) & 0x3f) | 0x80);
    return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($d), 4));
}

/**
 * Get or create a stable device_id cookie (UUID v4 style).
 * NOTE: Keep cookie name 'device_id' to match your existing use.
 */
function device_get_id(): string {
    $cookie = $_COOKIE['device_id'] ?? '';

    // Accept only uuid-like values
    if (!preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i', $cookie)) {
        $cookie = device_uuid4();

        // 2 years cookie
        $cookieParams = [
            'expires'  => time() + 60*60*24*730,   // ~2 years
            'path'     => '/',
            // Keep your explicit domain (subdomain cookie). If you later want wallet+apps
            // to share, use '.bitcardo.com' and ensure both apps are on HTTPS.
            'domain'   => 'wallet.bitcardo.com',
            'secure'   => !empty($_SERVER['HTTPS']), // only mark secure if HTTPS
            'httponly' => true,                      // JS doesn't need to read this
            'samesite' => 'Lax',
        ];
        setcookie('device_id', $cookie, $cookieParams);
        $_COOKIE['device_id'] = $cookie; // make it visible this request
    }
    return $cookie;
}

/**
 * Build a coarse fingerprint (UA only for now).
 */
function device_fingerprint(): string {
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
    return hash('sha256', $ua);
}

/**
 * Human label (UA-based).
 */
function device_label(): string {
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    if (stripos($ua, 'iPhone') !== false)   return 'iPhone';
    if (stripos($ua, 'iPad') !== false)     return 'iPad';
    if (stripos($ua, 'Android') !== false)  return 'Android';
    if (stripos($ua, 'Windows') !== false)  return 'Windows';
    if (stripos($ua, 'Mac OS') !== false || stripos($ua, 'Macintosh') !== false) return 'macOS';
    return 'Browser';
}

/**
 * Small helper to “touch” last seen and IP.
 */
function device_touch_seen(mysqli $conn, int $userId, string $deviceId): void {
    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    $sql = "UPDATE user_devices SET last_ip=?, last_seen_at=NOW() WHERE user_id=? AND device_id=?";
    if ($stmt = $conn->prepare($sql)) {
        $stmt->bind_param('sis', $ip, $userId, $deviceId);
        $stmt->execute();
        $stmt->close();
    }
}

/**
 * Check if this device is trusted for the user (by cookie + expiry + trusted flag).
 * If trusted, we also update last_seen_at.
 */
function device_is_trusted(mysqli $conn, int $userId): bool {
    $deviceId = device_get_id();
    $sql = "SELECT trusted_until FROM user_devices
            WHERE user_id=? AND device_id=? AND trusted=1
            LIMIT 1";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param('is', $userId, $deviceId);
    $stmt->execute();
    $stmt->bind_result($trustedUntil);
    $ok = false;
    if ($stmt->fetch()) {
        $ok = $trustedUntil && (new DateTimeImmutable($trustedUntil) > new DateTimeImmutable());
    }
    $stmt->close();

    if ($ok) {
        device_touch_seen($conn, $userId, $deviceId);
    }
    return $ok;
}

/**
 * Mark device trusted for +$trustDays days (upsert).
 */
function device_mark_trusted(mysqli $conn, int $userId, int $trustDays): void {
    $deviceId   = device_get_id();
    $finger     = device_fingerprint();
    $label      = device_label();
    $ip         = $_SERVER['REMOTE_ADDR'] ?? '';
    $trustedTil = (new DateTimeImmutable("+{$trustDays} days"))->format('Y-m-d H:i:s');

    $sql = "INSERT INTO user_devices
              (user_id, device_id, device_fingerprint, device_label, first_ip, last_ip, last_seen_at, trusted_until, trusted)
            VALUES
              (?, ?, ?, ?, ?, ?, NOW(), ?, 1)
            ON DUPLICATE KEY UPDATE
              device_fingerprint=VALUES(device_fingerprint),
              device_label=VALUES(device_label),
              last_ip=VALUES(last_ip),
              last_seen_at=NOW(),
              trusted_until=VALUES(trusted_until),
              trusted=1";
    $stmt = $conn->prepare($sql);
    $stmt->bind_param('issssss', $userId, $deviceId, $finger, $label, $ip, $ip, $trustedTil);
    $stmt->execute();
    $stmt->close();
}

/**
 * (Optional) Revoke ALL trusted devices for the user (e.g., after password reset).
 */
function device_revoke_all(mysqli $conn, int $userId): void {
    $conn->query("UPDATE user_devices SET trusted=0, trusted_until=NOW() WHERE user_id=".(int)$userId);
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!