Pembaruan Otomatis, dan Mengapa Anda Membutuhkan Satu Lapisan Penandatanganan Lagi

Di Bagian 1, kita menyelesaikan pengaturan sertifikat Developer ID dan notarisasi. Dengan itu, Anda siap untuk mengirimkan aplikasi kepada pengguna untuk pertama kalinya. Namun aplikasi tidak selesai setelah satu rilis — Anda harus terus merilis versi baru yang memperbaiki bug dan menambahkan fitur.

Untuk aplikasi Mac App Store, App Store menangani pembaruan untuk Anda. Aplikasi yang didistribusikan langsung tidak mendapatkan itu, jadi Anda harus membangun fitur pembaruan otomatis ke dalam aplikasi sendiri. Di macOS, standar de facto untuk peran ini adalah framework open-source Sparkle. Dengan Sparkle terpasang, aplikasi secara berkala memeriksa “feed pembaruan (appcast),” dan jika ada versi baru, aplikasi memberi tahu pengguna, mengunduhnya, dan menginstalnya.

Ini menimbulkan pertanyaan. Anda sudah menandatangani aplikasi dengan sertifikat Developer ID yang dibuat di Bagian 1, jadi mengapa Anda membutuhkan kunci lain lagi?

Alasannya adalah kedua tanda tangan memverifikasi hal yang berbeda.

  • Sertifikat Developer ID — digunakan oleh Gatekeeper macOS untuk memutuskan “apakah boleh menginstal aplikasi ini?”
  • Kunci EdDSA Sparkle — digunakan oleh Sparkle di dalam aplikasi untuk memutuskan “apakah file pembaruan yang baru saja diunduh benar-benar dibuat oleh pengembang aplikasi ini?

Pembaruan otomatis adalah operasi yang sensitif dari segi keamanan: aplikasi mengunduh file dari internet dan menimpa dirinya sendiri. Jika seseorang mencegat server pembaruan atau jalur komunikasi dan menyelipkan file palsu, itu menjadi masalah serius. Untuk mencegah hal ini, Sparkle hanya menerima pembaruan yang ditandatangani dengan kunci privat yang hanya dipegang oleh pengembang, dan menolak menginstal apa pun yang tanda tangannya tidak cocok. Ini secara efektif adalah lapisan verifikasi terpisah dari sertifikat.

Dalam artikel ini, kita akan membuat pasangan kunci EdDSA (Ed25519) yang akan digunakan untuk verifikasi tersebut.

Seperti di Bagian 1, semua nama dan jalur (FocusTimer, example.com, dll.) adalah nilai contoh. Dalam praktiknya, gantikan dengan informasi aplikasi Anda sendiri.

Prasyarat — Sparkle Harus Sudah Ditambahkan ke Aplikasi

Sebelum membuat kunci, framework Sparkle harus sudah ditambahkan sebagai dependensi proyek aplikasi Anda. Jika belum, tambahkan di Xcode melalui Swift Package Manager (SPM).

  1. Buka proyek Anda di Xcode → File → Add Package Dependencies…
  2. Masukkan alamat repositori di kotak pencarian: https://github.com/sparkle-project/Sparkle
  3. Atur aturan versi ke 2.x (versi mayor terbaru) dan tambahkan

Setelah melakukan ini, build proyek sekali agar SPM mengunduh paket Sparkle. Alat baris perintah yang dibundel bersamanya adalah kunci untuk langkah berikutnya.

Langkah 1 — Temukan Alat Baris Perintah Sparkle

Paket Sparkle menyertakan alat baris perintah yang digunakan untuk pembuatan kunci dan penandatanganan. Alat-alat ini berada di dalam folder tempat SPM mengunduh paket, tetapi lokasi tersebut bervariasi tergantung versi Xcode dan pengaturan DerivedData. Jadi lebih aman untuk menemukannya secara langsung.

SPARKLE_BIN=$(find ~/Library/Developer/Xcode/DerivedData \
  -path "*/artifacts/sparkle/Sparkle/bin" -type d 2>/dev/null | head -1)
echo "$SPARKLE_BIN"

Jika satu jalur tercetak, berhasil. Jika tidak ada yang muncul, Anda melewatkan langkah “build proyek sekali” di atas — jalankan build di Xcode lalu coba lagi.

Di dalam folder ini terdapat alat-alat berikut.

  • generate_keys — membuat, mencadangkan, memulihkan, dan memverifikasi kunci penandatanganan (digunakan dalam artikel ini)
  • sign_update — menandatangani file pembaruan (digunakan saat rilis sebenarnya)
  • generate_appcast — membuat feed pembaruan (appcast.xml) (muncul di Bagian 3)

Langkah 2 — Buat Kunci Penandatanganan

Sekarang buat pasangan kunci.

"$SPARKLE_BIN/generate_keys"

Output yang mirip dengan berikut muncul.

Generating a new signing key...
A key has been generated and saved in your keychain. Add the SUPublicEDKey
key to the Info.plist of each app for which you intend to use Sparkle...

    <key>SUPublicEDKey</key>
    <string>5vT3kQbA9mZ0wR1yX8cD2eF4gH6jK7lN0pS2uV5xW8c=</string>

Satu perintah ini membuat dua kunci.

  • Kunci publik (public key) — nilai SUPublicEDKey yang ditampilkan dalam output di atas. Ini bukan rahasia, dan ini adalah kunci yang akan Anda sematkan ke dalam aplikasi.
  • Kunci privat (private key) — tidak muncul di layar. Ini secara otomatis tersimpan di Keychain macOS sebagai item bernama “Private key for signing Sparkle updates.” Ini adalah rahasia sejati yang tidak boleh pernah dibiarkan di disk sebagai file teks biasa.

Menyematkan Kunci Publik ke Aplikasi

Masukkan string kunci publik dari output ke Info.plist aplikasi. Untuk aplikasi contoh, tambahkan kunci-kunci berikut ke FocusTimer-Info.plist.

<key>SUFeedURL</key>
<string>https://updates.example.com/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>5vT3kQbA9mZ0wR1yX8cD2eF4gH6jK7lN0pS2uV5xW8c=</string>
  • SUPublicEDKey — kunci publik yang baru saja Anda buat. Aplikasi menggunakan kunci ini untuk memverifikasi tanda tangan pembaruan yang diunduh.
  • SUFeedURL — alamat feed pembaruan. Domain ini belum ada; kita membuatnya di Bagian 3. Untuk sekarang, ini hanyalah placeholder.

Karena kunci publik disematkan di aplikasi dan hanya pengembang yang memegang kunci privat, aplikasi hanya akan menerima pembaruan yang ditandatangani dengan kunci privat. Inilah struktur inti dari verifikasi pembaruan Sparkle.

Langkah 3 — Cadangkan Kunci Privat (Wajib!)

Jika Anda melewatkan langkah ini, Anda mungkin akan sangat menyesalinya nanti.

Kunci privat tersimpan di Keychain, jadi tidak masalah di komputer yang Anda gunakan sekarang. Tetapi jika Anda kehilangan komputer, disk rusak, atau Anda menginstal ulang macOS, kunci ini ikut hilang bersamanya.

Apa yang terjadi jika kunci privat hilang? Pembaruan yang ditandatangani dengan kunci baru akan ditolak oleh aplikasi pengguna yang sudah ada (aplikasi dengan kunci publik lama yang disematkan). Dengan kata lain, Anda tidak akan pernah bisa mengirim pembaruan otomatis lagi kepada pengguna yang sudah menjalankan aplikasi Anda. Satu-satunya pilihan adalah memberi tahu setiap pengguna secara individual, “silakan unduh versi baru sendiri dan instal ulang.”

Jadi cadangkan kunci segera setelah Anda membuatnya.

"$SPARKLE_BIN/generate_keys" -x ~/focustimer-sparkle-private.key
cat ~/focustimer-sparkle-private.key

String base64 satu baris yang dicetak oleh cat adalah kunci privat. Contoh:

Hn4Kp9Lr2Qs5Tv8Wx1Yz3Ab6Cd0Ef7Gh4Ij5Kl8MnQ0=

Simpan string ini sebagai catatan aman (secure note) di manajer kata sandi seperti 1Password. Beri catatan tersebut nama yang mudah ditemukan nanti, seperti FocusTimer Sparkle EdDSA Private Key.

Segera setelah mengonfirmasi penyimpanan, hapus file teks biasa yang tersisa di disk.

rm ~/focustimer-sparkle-private.key

Aturannya adalah tidak pernah membiarkan kunci privat ada di disk sebagai file teks biasa. Simpan cadangannya hanya di dalam manajer kata sandi yang terenkripsi.

Jebakan Utama — Simbol % Bukan Bagian dari Kunci

Saat Anda mencetak kunci dengan cat, terminal (terutama zsh) mungkin menambahkan simbol % di akhir baris.

Hn4Kp9Lr2Qs5Tv8Wx1Yz3Ab6Cd0Ef7Gh4Ij5Kl8MnQ0=%

% ini hanyalah indikator shell bahwa “output berakhir tanpa baris baru” — bukan bagian dari kunci. Jika Anda menyalin % ini ke cadangan Anda, kunci akan rusak saat Anda memulihkannya nanti. String base64 biasanya diakhiri dengan =, jadi kecualikan % setelah = saat menyimpan.

Langkah 4 — Memulihkan di Komputer Lain

Saat Anda perlu mem-build aplikasi di komputer baru, masukkan kembali kunci privat yang dicadangkan ke Keychain.

echo "string_base64_cadangan_anda" > ~/focustimer-sparkle-private.key
"$SPARKLE_BIN/generate_keys" -f ~/focustimer-sparkle-private.key
rm ~/focustimer-sparkle-private.key

Opsi -f berarti “impor kunci dalam file ke Keychain.” Setelah pemulihan selesai, hapus file teks biasa di sini juga, segera.

Langkah 5 — Verifikasi

Periksa bahwa kunci terinstal dengan benar.

"$SPARKLE_BIN/generate_keys" -p

Satu baris yang berisi kunci publik dicetak. Nilai ini harus persis cocok dengan nilai yang Anda masukkan ke SUPublicEDKey di Info.plist di Langkah 2. Jika berbeda, kunci publik yang disematkan di aplikasi dan kunci penandatanganan aktual tidak sinkron, dan verifikasi pembaruan akan gagal.

Rangkuman Bagian 2

Jika Anda telah mengikuti sejauh ini, Anda sekarang memiliki hal-hal berikut.

  • ✅ Pasangan kunci EdDSA Sparkle yang dibuat (kunci publik + kunci privat)
  • ✅ Kunci publik disematkan di Info.plist aplikasi (SUPublicEDKey)
  • ✅ Kunci privat dicadangkan dengan aman di manajer kata sandi
  • ✅ Familiar dengan cara memulihkannya di komputer lain

Aplikasi sekarang memiliki cara untuk memverifikasi “apakah pembaruan yang diunduh asli.” Tetapi satu hal masih hilang. Di Bagian 2 Anda menulis https://updates.example.com/appcast.xml untuk SUFeedURL, tetapi masih belum ada apa pun di alamat tersebut.

Di bagian berikutnya, kita akan membuat repositori publik tempat feed pembaruan (appcast.xml) dan file .dmg akan disimpan, menghubungkannya ke domain yang kita kendalikan, dan menyelesaikan pengaturan build — menyelesaikan konfigurasi satu kali.