<?php
/**
 * Apple JWT helpers (dependency-free).
 *  - base64url encode/decode
 *  - generate the Apple "client secret" (an ES256-signed JWT)
 *  - decode an id_token payload
 *
 * Apple's client secret is a short-lived JWT signed with your .p8 EC key
 * (algorithm ES256). openssl_sign() emits a DER-encoded ECDSA signature, but
 * JWT requires the raw r||s form, so we convert it (dabil_der_to_raw).
 */

function dabil_b64url_encode(string $bin): string
{
    return rtrim(strtr(base64_encode($bin), '+/', '-_'), '=');
}

function dabil_b64url_decode(string $txt): string
{
    $pad = strlen($txt) % 4;
    if ($pad) {
        $txt .= str_repeat('=', 4 - $pad);
    }
    return base64_decode(strtr($txt, '-_', '+/')) ?: '';
}

/** Convert an ECDSA DER signature to the raw fixed-length r||s (64 bytes). */
function dabil_der_to_raw(string $der): string
{
    $offset = 0;
    if (ord($der[$offset++]) !== 0x30) {           // SEQUENCE
        return $der;
    }
    // Skip sequence length (handle long form just in case).
    $len = ord($der[$offset++]);
    if ($len & 0x80) {
        $offset += ($len & 0x7f);
    }

    $readInt = function () use ($der, &$offset): string {
        $offset++;                                  // 0x02 INTEGER tag
        $l = ord($der[$offset++]);
        $v = substr($der, $offset, $l);
        $offset += $l;
        $v = ltrim($v, "\x00");                     // drop sign padding
        return str_pad($v, 32, "\x00", STR_PAD_LEFT);
    };

    $r = $readInt();
    $s = $readInt();
    return $r . $s;
}

/** Build and sign the Apple client-secret JWT. Returns '' on failure. */
function dabil_apple_client_secret(): string
{
    if (!is_readable(APPLE_PRIVATE_KEY_PATH)) {
        return '';
    }
    $pem = file_get_contents(APPLE_PRIVATE_KEY_PATH);
    $key = openssl_pkey_get_private($pem);
    if ($key === false) {
        return '';
    }

    $now    = time();
    $header = ['alg' => 'ES256', 'kid' => APPLE_KEY_ID];
    $claims = [
        'iss' => APPLE_TEAM_ID,
        'iat' => $now,
        'exp' => $now + 3600,                       // 1 hour is plenty
        'aud' => 'https://appleid.apple.com',
        'sub' => APPLE_CLIENT_ID,
    ];

    $signingInput = dabil_b64url_encode(json_encode($header)) . '.' .
                    dabil_b64url_encode(json_encode($claims));

    $der = '';
    if (!openssl_sign($signingInput, $der, $key, OPENSSL_ALGO_SHA256)) {
        return '';
    }

    return $signingInput . '.' . dabil_b64url_encode(dabil_der_to_raw($der));
}

/** Decode (NOT verify) a JWT's payload into an array. */
function dabil_jwt_payload(string $jwt): array
{
    $parts = explode('.', $jwt);
    if (count($parts) < 2) {
        return [];
    }
    return json_decode(dabil_b64url_decode($parts[1]), true) ?: [];
}
