🍎
【Appleサブスクリプションオファー】プロモーションオファー署名の作成方法
Appleのサブスクリプションオファーのプロモーションオファーに関しての情報がなかった。
これが、日本初の資料。
プロモーションオファーとは
WWDC 2019動画
Apple公式ドキュメント
対象となるのは、そのサブスクリプションを現在利用している、または過去に利用したことがあるお客様です。
これらのオファーによって、ユーザー数の拡大や維持のため、
独自のプロモーションを柔軟に行うことができるようになります。
キャンペーンを通じて、サブスクリプションをキャンセルした利用者に再サブスクリプションを促したり、
別のサブスクリプションへのアップグレードを特別価格で提供したりすることができます。
準備
Apple公式ドキュメント
サブスクリプションオファーの設定
実装
※今回は、サーバーサイド(Ruby)での署名作成に関してのみ記載する
Apple公式ドキュメント
プロモーションオファー用の署名の生成
署名の生成に必要なもの
■appBundleID
環境変数で持つ
■keyIdentifier
環境変数で持つ
■productIdentifier
アプリ側からパラメータでもらう
■offerIdentifier
アプリ側からパラメータでもらう
■applicationUsername
アプリ側からパラメータでもらう
■nonce
サーバー側で生成する
■timestamp
サーバー側で生成する
署名
署名の生成
サンプルコード (Ruby)
本来はメソッドで分割するが、わかりやすさを重視する
require 'openssl'
require 'base64'
require 'securerandom'
require 'json'
# 環境変数として読み込むが、あえて記載する
private_key = '-----BEGIN PRIVATE KEY-----xxxxxxxxxxxxxxxxxxx-----END PRIVATE KEY-----'
# 環境変数から読み込んだ秘密鍵の改行コードがエスケープされてしまうのを防ぐ
private_key = OpenSSL::PKey::EC.new(private_key.gsub(/\\n/, "\n"))
app_bundle_id = 'xxxx'
key_identifier = 'xxxx'
product_identifier = 'xxxx'
offer_identifier = 'xxxx'
application_username = 'xxxx'
nonce = SecureRandom.uuid
timestamp = (Time.current.to_f * 1000).to_i.to_s
# 不可視の分離文字('\u2063')をパラメータの間にはさみ、結合する
payload = app_bundle_id + "\u{2063}" +
key_identifier + "\u{2063}" +
product_identifier + "\u{2063}" +
offer_identifier + "\u{2063}" +
application_username + "\u{2063}" +
nonce + "\u{2063}" +
timestamp
# 署名
# Ruby2.4.0以降であれば
# signature = private_key.sign(digest, data)
# SHA-256ハッシュを使って署名
signature = private_key.dsa_sign_asn1(OpenSSL::Digest::SHA256.digest(payload))
# base64にエンコード
# strict_encode64を使い、改行コードを消す
signature_base64 = Base64.strict_encode64(signature)
# 検証
# OpenSSL::PKey::ECオブジェクトを生成
ec = OpenSSL::PKey::EC.new(private_key.group)
ec.public_key = private_key.public_key
# SHA-256ハッシュで検証
digest = OpenSSL::Digest::SHA256.new
# payloadを秘密鍵で署名したその署名文字列がsignatureであることを公開鍵を使って検証
ec.verify(digest, signature, payload)
result = { key_identifier: key_identifier, nonce: nonce, timestamp: timestamp, signature: signature_base64 }.to_json
楕円曲線デジタル署名アルゴリズム(ECDSA)について
最初はruby_ecdsaというgemを使おうかと検討していた
require 'ecdsa'
require 'securerandom'
require 'digest/sha2'
group = ECDSA::Group::Secp256k1
private_key = 1 + SecureRandom.random_number(group.order - 1)
public_key = group.generator.multiply_by_scalar(private_key)
message = 'ECDSA is cool.'
digest = Digest::SHA2.digest(message)
temp_key = 1 + SecureRandom.random_number(group.order - 1)
signature = ECDSA.sign(group, private_key, digest, temp_key)
valid = ECDSA.valid_signature?(public_key, digest, signature)
puts "valid: #{valid}"
が、秘密鍵が数値を想定したつくりになっていたので使用を見送った
Apple公式の署名作成サンプル
JavaScriptとNode.jsを使ったサンプル
サーバを起動して、アクセスするとレスポンスが返る
Discussion