Подтвердить что ты не робот

Как отправлять сообщения APN с помощью APN Auth Key и стандартных инструментов CLI?

Недавно Apple добавила новый метод аутентификации в APNS (Apple Authentication Key (песочница и производство)).

введите описание изображения здесь

Загруженный ключ - это файл .p8 с закрытым ключом:

$ cat APNSAuthKey_3HHEB343FX.p8
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBH...Already.Revoked...lHEjCX1v51W
-----END PRIVATE KEY-----

Я использую APN-сообщения, используя старый метод, добавляя их в цепочку ключей, запрашивая сертификат и используя OpenSSL для отправки сообщений на gateway.production.push.apple.com:2195.

Как отправлять push-уведомления с помощью стандартных инструментов CLI Linux (OpenSSL, Python и т.д.) с использованием нового формата?

4b9b3361

Ответ 1

Если у вас есть curl с поддержкой HTTP/2 и openssl с поддержкой ECDSA, установленный на вашем компьютере, вы можете использовать следующий скрипт для тестирования push-уведомлений с использованием ключа авторизации APN:

#!/bin/bash

deviceToken=b27371497b85611baf9052b4ccfb9641ab7fea1d01c91732149c99cc3ed9342f

authKey="./APNSAuthKey_ABC1234DEF.p8"
authKeyId=ABC1234DEF
teamId=TEAM123456
bundleId=com.example.myapp
endpoint=https://api.development.push.apple.com

read -r -d '' payload <<-'EOF'
{
   "aps": {
      "badge": 2,
      "category": "mycategory",
      "alert": {
         "title": "my title",
         "subtitle": "my subtitle",
         "body": "my body text message"
      }
   },
   "custom": {
      "mykey": "myvalue"
   }
}
EOF

# --------------------------------------------------------------------------

base64() {
   openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}

sign() {
   printf "$1" | openssl dgst -binary -sha256 -sign "$authKey" | base64
}

time=$(date +%s)
header=$(printf '{ "alg": "ES256", "kid": "%s" }' "$authKeyId" | base64)
claims=$(printf '{ "iss": "%s", "iat": %d }' "$teamId" "$time" | base64)
jwt="$header.$claims.$(sign $header.$claims)"

curl --verbose \
   --header "content-type: application/json" \
   --header "authorization: bearer $jwt" \
   --header "apns-topic: $bundleId" \
   --data "$payload" \
   $endpoint/3/device/$deviceToken

ПРИМЕЧАНИЕ: Я использую небольшой вариант этого скрипта для тестирования на macOS с доморощенными версиями curl и openssl: http://thrysoee.dk/apns/

Ответ 2

Вы можете отправить push-уведомление с помощью NODE JS, используя ключ аутентификации Apple Push Notification (песочница и производство). Apple предоставила учебное пособие в этой ссылке

В этом учебном курсе есть все шаги по созданию ключа аутентификации Apple Push Notification и настройка локального сервера для запуска NODE JS-кода для отправки push-уведомления. Вы можете запустить код на своем локальном компьютере и протестировать push-уведомление.

Надеюсь, это поможет.

Ответ 3

Вуаля в PHP, как это выглядит с curl и HTTP/2. Этот скрипт возвращает код состояния 200 ok вместе с сгенерированным идентификатором токена.

// THE FINAL SCRIPT WITHOUT DEPENDENCIES!!! ...except curl with http2
$device_token = "a0abd886etc...";
//echo $key;
$kid      = "YOURKEYID";
$teamId   = "YOURTEAMID";
$app_bundle_id = "your.app.bundle";
$base_url = "https://api.development.push.apple.com";

$header = ["alg" => "ES256", "kid" => $kid];
$header = base64_encode(json_encode($header));

$claim = ["iss" => $teamId, "iat" => time()];
$claim = base64_encode(json_encode($claim));

$token = $header.".".$claim;
// key in same folder as the script
$filename = "KeyFromApple.p8";
$pkey     = openssl_pkey_get_private("file://{$filename}");
$signature;
openssl_sign($token, $signature, $pkey, 'sha256');
$sign = base64_encode($signature);

$jws = $token.".".$sign;

$message = '{"aps":{"alert":"You are welcome.","sound":"default"}}';

function sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws) {

    $url = "{$base_url}/3/device/{$device_token}";
    // headers
    $headers = array(
        "apns-topic: {$app_bundle_id}",
        'Authorization: bearer ' . $jws
    );
    // other curl options
    curl_setopt_array($curl, array(
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
        CURLOPT_URL => $url,
        CURLOPT_PORT => 443,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POST => TRUE,
        CURLOPT_POSTFIELDS => $message,
        CURLOPT_RETURNTRANSFER => TRUE,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_SSL_VERIFYPEER => FALSE,
        CURLOPT_HEADER => 1
    ));
    // go...
    $result = curl_exec($curl);
    if ($result === FALSE) {
        throw new Exception("Curl failed: " .  curl_error($curl));
    }
    print_r($result."\n");
    // get response
    $status = curl_getinfo($curl);
    return $status;
}
// open connection
$curl = curl_init();
sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws);

Ответ 4

Ответ, предоставленный Николасом Манзини, хотя и был полезным, но не полностью помог мне. Я также хотел использовать командную строку curl. В частности, чтение в файле .p8 вызывало некоторые проблемы. Модифицированная версия:

<?php

$teamid = 'YOURTEAMID';
$keyid = 'A464FN6T93';     // in the name of the file downloaded from Apple Certs

// since it is a universal key, I wanted this in a location accessible to several accounts
$keyFile = '/path/to/file/AuthKey_A464FN6T93.p8';

$privateKey = openssl_pkey_get_private('file://' . $keyFile);

if (! $privateKey) {
    die('could not find: ' . $keyFile);
}

$header = ['alg' => 'ES256', 'kid' => $keyid];
$header = base64_encode(json_encode($header));

$claim = ['iss' => $teamid, 'iat' => time()];
$claim = base64_encode(json_encode($claim));

$tok = $header . '.' . $claim;

// pass in empty $signature, 2nd line below fills it
$signature = '';
$result = openssl_sign($tok, $signature, $privateKey, OPENSSL_ALGO_SHA256);      //  'sha256'
if (! $result) {
    die('unable to create signature');
}

$sign = base64_encode($signature);

openssl_free_key($privateKey);

$jwt = $tok . '.' . $sign;

foreach($tokens as $token) {
    $cmd = '\
    /usr/local/bin/curl -v \
    -d \'{"aps":{"alert":{"title":"Notification Title","body":"You are being notified!"},"sound":"default"}}\' \
    -H "apns-topic: com.app.bundle.id" \
    -H "authorization: bearer ' . $jwt . '" \
    -H "content-type:application/json" \
    --http2 \
    https://api.push.apple.com/3/device/' . $token . ' 2>&1';    // ending w/ 2>&1, sends output to $output

    exec($cmd, $output, $return);

    if ($return != 0) {
        // be notified of error
    }
    else {
        foreach($output as $line) {
            if (strpos($line, 'apns-id')) {
                $apns = $line;
            }
        }
    }
}

?>