تأیید کننده کلید برای Android یک راه یکپارچه و امن برای کاربران فراهم می کند تا تأیید کنند که با شخص مناسب در برنامه رمزگذاری شده سرتاسر (E2EE) شما ارتباط برقرار می کنند. با اجازه دادن به آنها برای تأیید صحت کلیدهای رمزگذاری عمومی مخاطب از طریق یک رابط کاربری قابل اعتماد و سازگار سیستم، از کاربران در برابر حملات مرد میانی محافظت می کند.
این ویژگی توسط Key Verifier ارائه میشود، یک سرویس سیستمی که بخشی از خدمات سیستم Google است و با استفاده از فروشگاه Play توزیع میشود. این به عنوان یک مخزن متمرکز و روی دستگاه برای کلیدهای عمومی E2EE عمل می کند.
چرا باید با Key Verifier یکپارچه شوید
- یک UX یکپارچه ارائه دهید: به جای ایجاد جریان تأیید خود، میتوانید رابط کاربری استاندارد سیستم را راهاندازی کنید و به کاربران تجربهای ثابت و قابل اعتماد در همه برنامههایشان بدهید.
- افزایش اعتماد به نفس کاربر: وضعیت تأیید صریح و مبتنی بر سیستم به کاربران اطمینان می دهد که مکالمات آنها ایمن و خصوصی است.
- کاهش سربار توسعه: پیچیدگی تأیید کلید رابط کاربری، ذخیره سازی و مدیریت وضعیت را به سرویس سیستم تخلیه کنید.
اصطلاحات کلیدی
- lookupKey: یک شناسه غیرشفاف و ثابت برای یک مخاطب که در ستون LOOKUP_KEY ارائه دهنده مخاطبین ذخیره می شود. برخلاف
contact ID
، یکlookupKey
ثابت می ماند حتی اگر جزئیات تماس اصلی تغییر یا ادغام شوند، و آن را به روش توصیه شده برای ارجاع به مخاطب تبدیل می کند. - accountId: یک شناسه مخصوص برنامه برای حساب کاربری در دستگاه. این شناسه توسط برنامه شما تعریف شده است و به تمایز بین چندین حساب که ممکن است یک کاربر داشته باشد کمک می کند. این به کاربر در رابط کاربری نمایش داده میشود، توصیه میشود از چیزی معنادار مانند شماره تلفن، آدرس ایمیل یا دسته کاربر استفاده کنید.
- deviceId: یک شناسه منحصر به فرد برای یک دستگاه خاص مرتبط با حساب کاربری. این به کاربر امکان می دهد چندین دستگاه داشته باشد که هر کدام مجموعه ای از کلیدهای رمزنگاری خاص خود را دارند. لزوماً یک دستگاه فیزیکی را نشان نمی دهد، اما می تواند راهی برای تمایز بین چندین کلید مورد استفاده برای یک حساب کاربری باشد.
شروع کردن
قبل از شروع، برنامه خود را طوری تنظیم کنید که با سرویس تأییدکننده کلید ارتباط برقرار کند.
اعلام مجوزها: در AndroidManifest.xml خود، مجوزهای زیر را اعلام کنید. شما همچنین باید این موارد را در زمان اجرا از کاربر درخواست کنید.
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
دریافت نمونه مشتری: نمونه ای از ContactKeys
را دریافت کنید که نقطه ورود شما به API است.
import com.google.android.gms.contactkeys.ContactKeys
val contactKeyClient = ContactKeys.getClient(context)
راهنمایی برای توسعه دهندگان برنامه های پیام رسانی
به عنوان یک توسعهدهنده برنامه پیامرسان، نقش اصلی شما انتشار کلیدهای عمومی کاربران و کلیدهای مخاطبین آنها در سرویس تأییدکننده کلید است.
کلیدهای عمومی کاربر را منتشر کنید
برای اینکه دیگران بتوانند کاربر شما را بیابند و تأیید کنند، کلید عمومی آنها را در مخزن موجود در دستگاه منتشر کنید. برای امنیت بیشتر، کلیدهایی را در Android Keystore ایجاد کنید.
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun publishSelfKey(
contactKeyClient: ContactKeyClient,
accountId: String,
deviceId: String,
publicKey: ByteArray
) {
try {
Tasks.await(
contactKeyClient.updateOrInsertE2eeSelfKey(
deviceId,
accountId,
publicKey
)
)
// Self key published successfully.
} catch (e: Exception) {
// Handle error.
}
}
کلیدهای عمومی را با مخاطبین مرتبط کنید
هنگامی که برنامه شما یک کلید عمومی برای یکی از مخاطبین کاربر دریافت می کند، باید آن را ذخیره کرده و با آن مخاطب در مخزن مرکزی مرتبط کنید. این اجازه می دهد تا کلید تأیید شود و به برنامه های دیگر امکان می دهد وضعیت تأیید را برای مخاطب نمایش دهند. برای انجام این کار، به lookupKey مخاطب از ارائه دهنده مخاطبین Android نیاز دارید. این معمولاً هنگام واکشی کلید از سرور توزیع کلید شما یا در طول همگامسازی دورهای کلیدهای محلی فعال میشود.
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun storeContactKey(
contactKeyClient: ContactKeyClient,
contactLookupKey: String,
contactAccountId: String,
contactDeviceId: String,
contactPublicKey: ByteArray
) {
try {
Tasks.await(
contactKeyClient.updateOrInsertE2eeContactKey(
contactLookupKey,
contactDeviceId,
contactAccountId,
contactPublicKey
)
)
// Contact's key stored successfully.
} catch (e: Exception) {
// Handle error.
}
}
بازیابی کلیدها و وضعیت تأیید
پس از اینکه کلیدها را منتشر کردید، کاربران می توانند آنها را از طریق اسکن شخصی QR Code تأیید کنند. رابط کاربری برنامه شما باید نشان دهد که آیا یک مکالمه از کلید تأیید شده استفاده می کند یا خیر. هر کلید دارای وضعیت تأیید است که می توانید از آن برای اطلاع رسانی رابط کاربری خود استفاده کنید.
درک حالت های تأیید:
UNVERIFIED
: این حالت پیش فرض برای هر کلید جدید است. یعنی کلید وجود دارد، اما کاربر هنوز صحت آن را تایید نکرده است. در رابط کاربری خود، باید این حالت را به عنوان یک حالت خنثی در نظر بگیرید و معمولاً نشانگر خاصی را نمایش نمیدهید.VERIFIED
: این وضعیت نشان دهنده سطح بالایی از اعتماد است. این بدان معناست که کاربر یک جریان تأیید را با موفقیت کامل کرده است (مانند اسکن کد QR) و تأیید کرده است که کلید متعلق به مخاطب مورد نظر است. در رابط کاربری خود، باید یک نشانگر واضح و مثبت، مانند علامت یا سپر سبز نشان دهید.VERIFICATION_FAILED
: این یک حالت هشدار است. این بدان معناست که کلید مرتبط با مخاطب با کلیدی که قبلاً تأیید شده است مطابقت ندارد. اگر مخاطبی دستگاه جدیدی دریافت کند، ممکن است این اتفاق بیفتد، اما میتواند یک خطر امنیتی بالقوه را نیز نشان دهد. در رابط کاربری خود، با یک اخطار برجسته به کاربر هشدار دهید و به او پیشنهاد دهید قبل از ارسال اطلاعات حساس، دوباره تأیید شود.
میتوانید وضعیت جمعی را برای همه کلیدهای مرتبط با یک مخاطب بازیابی کنید. توصیه می کنیم از VerificationState.leastVerifiedFrom()
برای حل وضعیت زمانی که چندین کلید وجود دارد استفاده کنید، زیرا به درستی VERIFICATION_FAILED
بر VERIFIED
اولویت می دهد.
- دریافت وضعیت کل در سطح تماس
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.contactkeys.constants.VerificationState
import com.google.android.gms.tasks.Tasks
suspend fun displayContactVerificationStatus(
contactKeyClient: ContactKeyClient,
contactLookupKey: String
) {
try {
val keysResult = Tasks.await(contactKeyClient.getAllE2eeContactKeys(contactLookupKey))
val states =
keysResult.keys.map { VerificationState.fromState(it.localVerificationState) }
val contactStatus = VerificationState.leastVerifiedFrom(states)
updateUi(contactLookupKey, contactStatus)
} catch (e: Exception) {
// Handle error.
}
}
- دریافت وضعیت کل در سطح حساب
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.contactkeys.constants.VerificationState
import com.google.android.gms.tasks.Tasks
suspend fun displayAccountVerificationStatus(
contactKeyClient: ContactKeyClient,
accountId: String
) {
try {
val keys = Tasks.await(contactKeyClient.getE2eeAccountKeysForAccount(accountId))
val states = keys.map { VerificationState.fromState(it.localVerificationState) }
val accountStatus = VerificationState.leastVerifiedFrom(states)
updateUi(accountId, accountStatus)
} catch (e: Exception) {
// Handle error.
}
}
تغییرات کلیدی را در زمان واقعی مشاهده کنید
برای تأیید اینکه رابط کاربری برنامه شما همیشه وضعیت اعتماد صحیح را نشان میدهد، باید به بهروزرسانیها گوش دهید. روش توصیه شده استفاده از API مبتنی بر جریان است، که هر زمان کلیدی برای حساب مشترک اضافه شده، حذف شود یا وضعیت تأیید آن تغییر کند، فهرست جدیدی از کلیدها را منتشر می کند. این به ویژه برای به روز نگه داشتن لیست اعضای یک مکالمه گروهی مفید است. وضعیت تأیید یک کلید زمانی می تواند تغییر کند که:
- کاربر یک جریان تأیید را با موفقیت کامل می کند (به عنوان مثال، اسکن کد QR).
- کلید مخاطب تغییر یافته و باعث می شود دیگر با مقدار تأیید شده قبلی مطابقت نداشته باشد.
fun observeKeyUpdates(contactKeyClient: ContactKeyClient, accountIds: List<String>) {
lifecycleScope.launch {
contactKeyClient.getAccountContactKeysFlow(accountIds)
.collect { updatedKeys ->
// A key was added, removed, or updated.
// Refresh your app's UI and internal state.
refreshUi(updatedKeys)
}
}
}
تأیید کلید حضوری را انجام دهید
امن ترین راه برای کاربران برای تأیید یک کلید از طریق تأیید حضوری است، اغلب با اسکن یک کد QR یا مقایسه یک سری اعداد. برنامه Key Verifier جریانهای استاندارد رابط کاربری را برای این فرآیند ارائه میکند که برنامه شما میتواند راهاندازی کند. پس از تلاش برای راستیآزمایی، API بهطور خودکار وضعیت تأیید کلید را بهروزرسانی میکند و اگر بهروزرسانیهای کلید را مشاهده میکنید به برنامه شما اطلاع داده میشود.
- فرآیند تأیید کلید برای یک مخاطب انتخاب شده توسط کاربر را شروع کنید،
PendingIntent
ارائه شده توسطgetScanQrCodeIntent
را با استفاده ازlookupKey
مخاطب انتخابی راه اندازی کنید. رابط کاربری به کاربر اجازه میدهد تمام کلیدهای مخاطب را تأیید کند.
import android.app.ActivityOptions
import android.app.PendingIntent
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun initiateVerification(contactKeyClient: ContactKeyClient, lookupKey: String) {
try {
val pendingIntent = Tasks.await(contactKeyClient.getScanQrCodeIntent(lookupKey))
val options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
.toBundle()
pendingIntent.send(options)
} catch (e: Exception) {
// Handle error.
}
}
- فرآیند تأیید کلید را برای یک حساب انتخاب شده توسط کاربر شروع کنید اگر کاربر می خواهد حسابی را تأیید کند که مستقیماً به یک مخاطب (یا حساب خاصی از یک مخاطب) مرتبط نیست، می توانید
PendingIntent
ارائه شده توسطgetScanQrCodeIntentForAccount
را راه اندازی کنید. این معمولاً برای نام بسته و شناسه حساب برنامه شما استفاده میشود.
import android.app.ActivityOptions
import android.app.PendingIntent
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun initiateVerification(contactKeyClient: ContactKeyClient, packageName: String, accountId: String) {
try {
val pendingIntent = Tasks.await(contactKeyClient.getScanQrCodeIntentForAccount(packageName, accountId))
// Allow activity start from background on Android SDK34+
val options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
.toBundle()
pendingIntent.send(options)
} catch (e: Exception) {
// Handle error.
}
}