Ana içeriğe geç

Verification (Doğrulama) 🎯

Bu kısımda Verifier bireyinin rollerini birlikte gerçekleştireceğiz.

alternative text

Bu işlemler:

  • 📥 Claimer tarafından verilen Presentation objesini teslim alacağız.
  • 🧐 Veri içerisindeki bilgilerin doğruluğunu kontrol edeceğiz.
  • 🔗 attestation işleminin doğru olup olmadığını zincirdeki hash değerini kontrol ederek onaylayacaksın. Bu attestation revoke da edilmiş olabilir. Bu duruma da bakmak gerekir.
  • 🤔 Gönderilen kimlik belgesinin Claimer tarafından gönderildiğine emin olacaksın.
🎉 Presentation: Şimdi ben PowerPoint Sunumu mu hazırlıcam birde yuha!

Presentation yani türkçesi ile sunum yaptığımız belge credential kullanılarak üretilecek belgedir. Bir presentation credential'in aksine içerisindeki belgelerin bazılarını saklayabilir. Bu bilgiler verifier'lar tarafından bilinmesi gerekmeyen bilgilerdir. Bu presentation aynı zamanda credential'in Claimer'a ait olduğunu kanıtlamaktadır.

🤓 Verification Neydi ya hatırlasak mı?

🔍 Bir Claimer, onaylanmış bir Kimlik Bilgisini (Credential) aldığında, bunu cüzdanlarında saklayabilir. Ancak bu kimlik bilgisinin bir kopyası yoksa, geçerliliğini nasıl belirleyebiliriz?

🔒 KILT, bir Claimer tarafından bir kimlik bilgisinde sunulan bilgilerin doğruluğunu ve geçerliliğini bir Doğrulayıcıya (Verifier) doğrulama olanağı tanır.

💡 Doğrulayıcı, bu üçüncü tarafa ya doğrudan kendi itibarlarına dayanarak ya da Onaylayıcının dahil olduğu bir delegasyon yapısı aracılığıyla güven duyar.

✅ Doğrulama süreci için:

🔑 Claimer, kimlik bilgisi ve tanımlayıcılarıyla ilişkilendirilmiş özel anahtara ihtiyaç duyar.

🔒 Doğrulayıcı, güvendiği Onaylayıcının tanımlayıcısına ihtiyaç duyar.

🔎 Doğrulama süreci sırasında, Claimer, Doğrulayıcıya üç şeyi kanıtlamayı amaçlar:

1️⃣ Kimlik bilgisi geçerlidir ve Onaylayıcı tarafından iptal edilmemiştir. 2️⃣ Kimlik bilgisinde belirtilen özellikler gerçekten Claimer'a aittir. 3️⃣ Kimlik bilgisi, belirli bir kullanım durumu için Doğrulayıcı için ilgili bilgileri içerir.

🎨 Presentation Oluşturma

Sadece Claimer'ı gönderip Verifier'ın doğrulmasını bekleyemez. Aynı zamanda bu credantial ile birlikte o credantial'in sahibi olduğunu kanıtlaması gerekmektedir. Bu sahipliği kanıtlamak için bir presentation oluşturup imzalaması gerekmektedir.

📦 Paketlerin Eklenmesi:

claimer/createPresentation.ts
import * as Kilt from '@kiltprotocol/sdk-js'

Bu satır, KILT SDK'sını projeye dahil eder. Bu SDK, KILT protokolü ile etkileşimde bulunmak için gerekli fonksiyonları ve sınıfları sağlar.

🛠 createPresentation Fonksiyonu:

claimer/createPresentation.ts
export async function createPresentation(
credential: Kilt.ICredential,
signCallback: Kilt.SignCallback,
challenge?: string
): Promise<Kilt.ICredentialPresentation> {

Bu fonksiyon, bir kimlik bilgisi sunumu oluşturmak için asenkron bir fonksiyondur. Üç parametre alır:

  • credential: Doğrulayıcıya sunulacak olan kimlik bilgisi.
  • signCallback: Kimlik bilgisi sunumunun imzalanması için kullanılacak geri çağırma fonksiyonu.
  • challenge: Opsiyonel bir parametre. Bu, doğrulayıcının talep ettiği rastgele bir dizedir ve kimlik bilgisi sunumunun doğrulayıcı tarafından talep edildiğini doğrulamak için kullanılır.

Fonksiyon, bir ICredentialPresentation nesnesi döndürür. Bu nesne, kimlik bilgisi sunumunun kendisidir.

🎨 Sunumu Oluşturma:

claimer/createPresentation.ts
return Kilt.Credential.createPresentation({
credential,
signCallback,
challenge
})

Bu kısım, Kilt.Credential.createPresentation fonksiyonunu kullanarak bir kimlik bilgisi sunumu oluşturur. Bu fonksiyon, yukarıda belirttiğimiz üç parametreyi alır ve bir kimlik bilgisi sunumu döndürür.

🌍 Geniş bir bakış yapalım

Şimdi kodun tamamına bakarak işlevini anlamak istersek:

claimer/createPresentation.ts
import * as Kilt from '@kiltprotocol/sdk-js'

export async function createPresentation(
credential: Kilt.ICredential,
signCallback: Kilt.SignCallback,
challenge?: string
): Promise<Kilt.ICredentialPresentation> {
// Create the presentation from credential, DID and challenge.
return Kilt.Credential.createPresentation({
credential,
signCallback,
challenge
})
}

Özetle, bu kod, bir kimlik bilgisi sunumu oluşturmayı sağlar. Bu sunum, bir doğrulayıcıya kimlik bilgisi sunarken kullanılır. Doğrulayıcı, bu sunumu kullanarak kimlik bilgisinin geçerliliğini ve kimlik bilgisi sahibinin kimliğini doğrulayabilir.

Verify (Onaylama)

Hadi verification kodumuzu yazalım. İlk olarak getChallange adında bir fonksiyon oluşturarak Claimer'ın imzalayarak credantial'a sahip olduğunu kanıtlayacağız.

Sonrasında verifyPresentation fonksiyonu ile gerçek doğrulama yani verification işlemini gerçekleştireceğiz. Bu işlemler için verify.ts dosyasını kullanacağız.

Paket ve Modül İçe Aktarmaları

verify.ts
import { config as envConfig } from 'dotenv'
import * as Kilt from '@kiltprotocol/sdk-js'
import { createPresentation } from './claimer/createPresentation'
import { generateKeypairs } from './claimer/generateKeypairs'
import { generateLightDid } from './claimer/generateLightDid'

Bu bölümde gerekli modüller ve paketler içe aktarılıyor. Özellikle dotenv kullanılarak ortam değişkenleri yükleniyor ve KILT SDK'sı ile diğer yardımcı fonksiyonlar dahil ediliyor. Belirtilen Paketleri daha öncesinde sırasıyla birlikte oluşturmuştuk.

Benzersiz Challenge Oluşturma

verify.ts
function getChallenge(): string {
return Kilt.Utils.UUID.generate()
}

Bu fonksiyon doğrulama süreci için benzersiz bir challenge oluşturur.

alternative text

Sunumu Doğrulama Fonksiyonu

verify.ts
async function verifyPresentation(
presentation: Kilt.ICredentialPresentation,
challenge: string,
trustedAttesterUris: Kilt.DidUri[]
): Promise<boolean> {

Doğrulama işlemi için bir fonksiyon oluşturarak işleme başlayabiliriz. Bu fonksiyon içerisine 3 adet parametre alacak olup True veya False olmak üzere bir Promise döndürecektir. Bu parametrelere bakılacak olunursa sırasıyla:

  1. presentation: Doğrulanacak kimlik bilgisi sunumu.
  2. challenge: Doğrulayıcının (Verifier) gönderdiği benzersiz değer. Bu, kimlik bilgisi sunumunun doğrulayıcı tarafından talep edildiğini doğrulamak için kullanılır.
  3. trustedAttesterUris: Güvendiğimiz onaylayıcıların (Attester) DID URI'lerinin listesi.

Bu fonksiyon bir credential presentation'u doğrular. Sunumun geçerli olup olmadığını, sahipliğini ve attestation'ın doğru olup olmadığını kontrol eder.

KILT API'sine Erişim:

verify.ts
Kilt.ConfigService.get('api')

Bu satır, KILT API'sine erişim sağlar.

Try Catch Yapısı

verify.ts
try {
.
.
.
} catch {
return false
}

Sonrasında devamında bizi ilk olarak bir try catch yapısı karşılar. Bu yapı attestationun doğru olup olmadığını kontrol etmektedir. Eğer doğru değilse yapı catch bloğuna yakalanır ve false değeri ile attestation'un zincirde olmadığı anlaşılır.

Sunumu Doğrulama:

verify.ts
const { revoked, attester } = await Kilt.Credential.verifyPresentation(
presentation,
{ challenge }
)

Try yapısının içerisine girildiğinde asıl doğrulamanın yapıldığı Kilt.Credential.verifyPresentation fonksiyonu bizi karşılamaktadır. Bu fonskiyon içerisine 2 adet değişken almaktadır. Bunlar sunulan presentation ve claimer'ın doğru birey olduğunu kanıtlamak için challange değerleridir.

Bu fonksiyon çıktı olarak 2 adet değer döndürür. Bu değerler attestation'un revoke edilip edilmediğini yani geçerliliğini yitirip yitirmediğini ifade eden değer olmaktayken diğer değer ise sunumu onaylayan attester'ın kim olduğudur.

verify.ts
if (revoked) {
return false
}

Eğer revoke değeri true ise yani credenatial geçerliliğini yitirmişse verification değeri false olarak çıktı verilir.

verify.ts
return trustedAttesterUris.includes(attester)

Bu satır, sunumu onaylayanın (attester) güvendiğimiz onaylayıcı listesinde (trustedAttesterUris) olup olmadığını kontrol eder. Eğer onaylayıcı bu listede ise, fonksiyon true döndürür, aksi takdirde false döndürür.

tehlike

Bir Verifier'ın kontrol etmesi gereken en önemli niteliklerden biri bir attester'a güvenip güvenmediğidir. Eğer güvenmiyorsa attestation zincirde olsun olmasın belgeyi kabul etmeyebilir. Bu durum attesterlar arasındaki güven yarışını oluşturur.

Doğrulama Akışı (Verification Flow)

verify.ts
export async function verificationFlow(
credential: Kilt.ICredential,
signCallback: Kilt.SignCallback,
trustedAttesterUris: Kilt.DidUri[] = []
) {

Bu fonksiyon, doğrulama sürecini yönetir. Öncelikle bir challenge oluşturur, ardından bir sunum oluşturur ve son olarak sunumu doğrular. Bu fonksiyonda içerisine 3 adet parametre almaktadır. Bu parametrelere teker teker bakılacak olunursa:

  1. credential: Kilt.ICredential: Doğrulayıcıya sunulacak olan kimlik bilgisi.
  2. signCallback: Kilt.SignCallback: Kimlik bilgisi sunumunun imzalanması için kullanılacak geri çağırma fonksiyonu.
  3. trustedAttesterUris: Kilt.DidUri[]: Doğrulayıcının güvendiği Onaylayıcıların (Attester) DID URI'lerinin listesi. Opsiyonel bir parametre ve varsayılan olarak boş bir liste ile başlar.
verificationFlow ve verifyPresentation Farkı Ne?

Aslında bu fonksiyonu oluşturarak tüm verification işlemini tek bir yerde yönetmekteyiz.

verificationFlow fonksiyonu, verifyPresentation fonksiyonunu içeren daha geniş bir doğrulama sürecini temsil eder. Tek başına verifyPresentation fonksiyonu sadece bir kimlik bilgisi sunumunun doğruluğunu kontrol eder. Ancak, gerçek dünyada bir doğrulama süreci, sadece sunumun doğruluğunu kontrol etmekten daha fazlasını gerektirir. İşte bu yüzden verificationFlow fonksiyonuna ihtiyaç duyarız.

verificationFlow fonksiyonunun amacı şunlardır:

  1. Benzersiz Bir Challenge Oluşturma: Doğrulayıcı, Claimer'a benzersiz bir challenge gönderir. Bu, sunumun gerçek zamanlı olarak ve belirli bir talep için oluşturulduğundan emin olmak için kullanılır.

  2. Sunumu Oluşturma: Claimer, bu challenge'ı kullanarak kimlik bilgisi sunumunu oluşturur ve imzalar.

  3. Sunumu Doğrulama: Doğrulayıcı, Claimer'dan alınan sunumu verifyPresentation fonksiyonu ile doğrular.

  4. Sonuçları Bildirme: Sunum doğruysa, doğrulayıcı başarılı bir doğrulama mesajı yazdırır. Aksi takdirde, başarısız bir doğrulama mesajı yazdırır.

Bu adımların her biri, merkezi olmayan bir kimlik doğrulama sürecinin kritik bileşenleridir. verifyPresentation fonksiyonu, bu sürecin sadece bir parçasıdır. verificationFlow fonksiyonu, bu adımları bir araya getirerek tam bir doğrulama süreci sağlar. Bu nedenle, sadece verifyPresentation fonksiyonuna değil, aynı zamanda bu adımları birleştiren verificationFlow fonksiyonuna da ihtiyaç duyarız.

Benzersiz Challenge Oluşturma

verify.ts
const challenge = getChallenge()

Bu satır, Claimer'a gönderilmek üzere benzersiz bir challenge oluşturur. Bu, sunumun gerçek zamanlı olarak ve belirli bir talep için oluşturulduğundan emin olmak için kullanılır. Bu fonksiyonu önceden oluşturmuştuk.

Kimlik Bilgisi Sunumu Oluşturma

verify.ts
const presentation = await createPresentation(
credential,
signCallback,
challenge
)

Bu satır, verilen kimlik bilgisi, imza geri çağırma fonksiyonu ve challenge kullanarak bir kimlik bilgisi sunumu oluşturur. Bu fonksiyonu claimer klasöründe birlikte oluşturmuştuk.

Sunumu Doğrulama:

verify.ts
const isValid = await verifyPresentation(
presentation,
challenge,
trustedAttesterUris
)

Bu satır, oluşturulan kimlik bilgisi sunumunu doğrular. Eğer sunum geçerliyse, isValid değeri true olacaktır.

Sonuçları Bildirme:

verify.ts
if (isValid) {
console.log('Verification successful! You are allowed to enter the club 🎉')
} else {
console.log('Verification failed! 🚫')
}

Bu kısım, sunumun doğruluğuna göre bir mesaj yazdırır. Eğer sunum doğruysa, başarılı bir doğrulama mesajı yazdırılır. Aksi takdirde, başarısız bir doğrulama mesajı yazdırılır.

Fonksiyon Ne yaptı?

verificationFlow() fonksiyonunun içeriğine baktığımızda aslında önceden yazdığımız fonksiyonları çalıştırırız. Sırasıyla

  • Claimer'ı onaylamak için bir Challange oluştururuz.
  • Claimer tarafından bir presentation oluştururuz.
  • Sunulan doğrulamayı Verifier olarak doğrularız.

Ana Fonksiyon

Bu bölüm bu dosyanın doğrudan çalıştırılması durumunda çalışacak olan ana fonksiyonu içerir. Ortam değişkenlerini yükler, KILT'a bağlanır ve doğrulama akışını başlatır.

verify.ts
if (require.main === module) {
;(async () => {

If yapısı ile modülün direkt olarak çalıştırılıp çalıştırılmadığını kontrol ederiz.

Ortam Değişkenlerinin Yüklenmesi:

verify.ts
envConfig()

Bu satır, .env dosyasındaki ortam değişkenlerini yükler. Bu, projede kullanılan çeşitli yapılandırma değerlerini saklamak için kullanılır.

KILT'a Bağlanma:

verify.ts
await Kilt.connect(process.env.WSS_ADDRESS as string)

Bu satır, KILT ağına bağlanır. Bağlantı adresi .env dosyasından alınır.

Claimer'ın DID Bilgilerini Oluşturma:

verify.ts
const claimerDidMnemonic = process.env.CLAIMER_DID_MNEMONIC as string
const { authentication } = generateKeypairs(claimerDidMnemonic)
const claimerDid = generateLightDid(claimerDidMnemonic)

Bu adımlar, Claimer'ın DID (Decentralized Identifier) bilgilerini oluşturmak için kullanılır. Bu, kimlik bilgisi sunumunu imzalamak için gereklidir.

uyarı

Fark etmiş olabileceğiniz gibi Claimer'ın DID'sini sorgularken yeni bir Light DID oluşturma fonksiyonu çalıştırdık. Bu durumun nedeni zincir üzerinde depolanmayan light DID'lerin her seferinde yeniden oluşuturulmaya açık olmasıdır.

verificationFlow() fonskiyonunun içerisinde presantation oluşturma fonksiyonu da çalışmaktadır. Bu nedenle Claimer bireyinin DID'sine ihtiyaç vardır.

Attester'ın DID Bilgilerini Yükleme:

verify.ts
const attesterDid = process.env.ATTESTER_DID_URI as Kilt.DidUri

Bu satır, Attester'ın DID URI'sini .env dosyasından alır.

Kimlik Bilgisini Yükleme:

verify.ts
const credential = JSON.parse(process.env.CLAIMER_CREDENTIAL as string)

Bu satır daha önceden attestation bölümünde kodumuzu çalıştırarak elde ettiğimiz ve .env dosyası içerisine kaydettiğimiz Credantial'ın kod içerisine eklenmesini sağlamaktadır.

Doğrulama Akışını Başlatma:

verify.ts
await verificationFlow(
credential,
async ({ data }) => ({
signature: authentication.sign(data),
keyType: authentication.type,
keyUri: `${claimerDid.uri}${claimerDid.authentication[0].id}`
}),
[attesterDid]
)

Bu satır, yukarıda tanımlanan verificationFlow fonksiyonunu çağırarak doğrulama sürecini başlatır.

Hata Yakalama:

verify.ts
} catch (e) {
console.log('Error in the verification flow')
throw e
}

Bu kısım, doğrulama süreci sırasında herhangi bir hata oluşursa bu hatayı yakalar ve bir hata mesajı yazdırır.


Kodun Bütünü

Kodun bütününe bir arada bakarak yapılan işlemleri incelememiz gerekirse:

verify.ts
import { config as envConfig } from 'dotenv'

import * as Kilt from '@kiltprotocol/sdk-js'

import { createPresentation } from './claimer/createPresentation'
import { generateKeypairs } from './claimer/generateKeypairs'
import { generateLightDid } from './claimer/generateLightDid'

function getChallenge(): string {
return Kilt.Utils.UUID.generate()
}

// Verifies validity, ownership & attestation.
async function verifyPresentation(
presentation: Kilt.ICredentialPresentation,
challenge: string,
trustedAttesterUris: Kilt.DidUri[]
): Promise<boolean> {
Kilt.ConfigService.get('api')

try {
const { revoked, attester } = await Kilt.Credential.verifyPresentation(
presentation,
{ challenge }
)

if (revoked) {
return false
}
// Returns true if no trusted attester URI is provided or, if it is, if it matches the one that issued the presented credential.
return trustedAttesterUris.includes(attester)
} catch {
return false
}
}

export async function verificationFlow(
credential: Kilt.ICredential,
signCallback: Kilt.SignCallback,
trustedAttesterUris: Kilt.DidUri[] = []
) {
// Verifier sends a unique challenge to the claimer 🕊
const challenge = getChallenge()

// Create a presentation and send it to the verifier 🕊
const presentation = await createPresentation(
credential,
signCallback,
challenge
)

// The verifier checks the presentation.
const isValid = await verifyPresentation(
presentation,
challenge,
trustedAttesterUris
)

if (isValid) {
console.log('Verification successful! You are allowed to enter the club 🎉')
} else {
console.log('Verification failed! 🚫')
}
}

// Don't execute if this is imported by another file.
if (require.main === module) {
;(async () => {
envConfig()

try {
await Kilt.connect(process.env.WSS_ADDRESS as string)
const claimerDidMnemonic = process.env.CLAIMER_DID_MNEMONIC as string
const { authentication } = generateKeypairs(claimerDidMnemonic)
const claimerDid = generateLightDid(claimerDidMnemonic)
const attesterDid = process.env.ATTESTER_DID_URI as Kilt.DidUri
// Load credential and claimer DID
const credential = JSON.parse(process.env.CLAIMER_CREDENTIAL as string)
await verificationFlow(
credential,
async ({ data }) => ({
signature: authentication.sign(data),
keyType: authentication.type,
keyUri: `${claimerDid.uri}${claimerDid.authentication[0].id}`
}),
[attesterDid]
)
} catch (e) {
console.log('Error in the verification flow')
throw e
}
})()
}

Sırasıyla işlevler:

  • Paketler eklenir.
  • Claimer'ın kendinin credential'a sahip olduğunu kanıtlamak için bir challange oluşturulur.
  • True ve False şeklinde bir çıktı veren Presantation onaylama fonksiyonu yazılır.
  • Baştan sona tüm işlemleri bir arada çalıştırmak için verificationFlow() fonksiyonu yazılır.
  • Fonksiyonun tek başına çalışırken neler yapacağını belirten fonksiyon yazılır.

Kodu Çalıştıralım!

Kodu çalıştırmak için terminalde kilt-rocks klasöründe bulunduğumuza emin olduktan sonra alt kısımdaki kodu çalıştırabiliriz:

yarn ts-node verify.ts
BAŞARDIN

Tüm bireyleri tüm kodları ile birlikte çalıştırdın ve hallettin! Seninle gurur duyuyorum! Hadi birlikte KILT-SDK ile projeler gerçekleştirelim!