Silme isteklerine doğru otomatikleştirme

*Bu içerik, yapay zekâ (beta) kullanılarak çevrildi ve hatalar içerebilir. Sayfayı İngilizce görüntülemek için buraya tıkla.

Genel Veri Koruma Yönetmeliği (GDPR) veri koruması ve gizlilik konusundaki Avrupa düzenlemesidir.Bireylerin kişisel verilerinin silinmesini talep etme hakkını verir, bilinen silme hakkı.Kullanıcılarınızın Kullanıcı Kimlikleri gibi herhangi bir Kişisel Tanımlayıcı Bilgi (Kişisel Tanıtıcı Bilgiler) saklarsanız, bu bilgileri bir kullanıcının isteği aldıktan sonra silerek GDPR gereksinimlerine uymanız gerekir.

Talepleri manuel olarak ele almak yerine, bir webhook kurabilirsiniz ve süreci otomatikleştirmek için üçüncü taraf bir mesajlaşma uygulamasındaki bir bot kullanabilirsiniz.PII verilerini depolamak için en yaygın yol olarak veri depoları, bu eğitim PII verilerini bir otomasyon çözümü olarak silmek için Guilded veya Discord'da bir bot oluşturmanın nasıl bir örneği verir Veri depoları için Açık Bulut API.

İş akışı

Bu eğitimi tamamladıktan sonra, kullanıcıların silme isteklerinin işlenmesini otomatikleştiren yerel çalışan özel bir program oluşturabilmelisiniz.Bu süreç için iş akışı şöyledir:

  1. Roblox Destek, bir kullanıcıdan silme isteği alır.
  2. Roblox webhook tetiklenir, içinde Kullanıcı Kimliği ve yüklenen deneylere katılan yerlerin bir listesi bulunan Başlangıç ​​Yeri Kimlikleri.
  3. Bot'unuz bu webhook bildirimlerini dinler, doğruluğunu doğrular ve verileri depolarda depolanan PII verilerini silmek için Açık Bulut API'yi kullanır.
  4. Bot, webhook mesajına Discord veya Guilded'de silme durumuyla yanıt verir.

Üçüncü taraf entegrasyonuyla bir webhook yapılandırın

Bir bot oluşturmadan önce, üçüncü taraf mesajlaşma uygulamasında webhook entegrasyonu ile bir sunucu kurun.Sonra yaratıcı panosundaki bir webhook yapılandırmak için sunucuyu kullanın.

Bir sunucu kurun

Aşağıdaki adımlar, Guilded veya Discord kullanarak sunucuyu nasıl kuracağınızı gösterir.

  1. Yeni bir Guilded sunucu oluşturun. Süreçle ilgilenmiyorsanız, Guilded Destek 'e bakın.
  2. Gizlilik ayarları altında, sunucuyu özel olarak ayarlayın.Sunucu varsayılan kanalınız olarak otomatik olarak özel bir #genel kanal oluşturur.
  3. Yeni sunucu ile bir webhook entegrasyonu oluşturun ve anlayabileceğiniz bir ad verin, örneğin GDPR Hook.Süreçle ilgilenmiyorsanız, Guilded Desteği görün.
  4. Webhook URL'sini kopyalayın ve güvenli bir dünyasaklayın.Sadece güvenilir takım üyelerinin erişmesine izin verin, çünkü URL'yi sızdırmak, kötü aktörlerin sahte mesajlar göndermesini ve kullanıcı verilerinizi potansiyel olarak silmesini sağlayabilir.

Roblox'ta bir webhook yapılandırın

Üçüncü taraf sunucu URL'sini aldıktan sonra, bunu bir webhook yapılandırmak için Yaratıcı Panosunda kullanın.Aşağıdaki ayarları yaptığınızdan emin olun:

  • Guilded veya Discord sunucu URL'sini Webhook URL'si olarak ekleyin.
  • Özel bir Gizli dahil edin.Yapılandırmayı bitirmek için bir sır gerekli olmasa da, kötü aktörlerin Roblox'u taklit etmesini ve verilerinizi silmesini engellemek için bir tane dahil etmelisiniz.Bir sırrın kullanımı hakkında daha fazla bilgi için, Webhook güvenliğini doğrula bakın.
  • Seç Silme İsteği Hakkı Tetikleyiciler altında.

Webhook'u Test Yanıtı düğmesini kullanarak test edebilirsiniz, böylece Roblox'un sunucunuzun #genel kanalından bir bildirim alıp almadığını görebilirsiniz.Bildirimi almazsanız, tekrar deneyin veya hata gidermek için sunucu ayarlarınızı kontrol edin.

Example notification on Guilded

Bir bot yapılandırın

Webhook'u ekledikten sonra, botu aşağıdaki adımlarla yapılandırmak için kullanın:

  1. Simgesine tıklayarak tüm sunucuların listesini açın veya kısayol kullan:

    • CtrlS Windows üzerinde.
    • S üzerinde Mac'te.
  2. Silme bildirimlerini almak için sunucunuzu seçin.

  3. Sunucu ana sayfası altındaki listeyi genişletin ve Botları Yönet seçin.

  4. Sunucu varsayılan kanalınız olarak otomatik olarak özel bir #genel kanal oluşturur.

  5. Bir bot oluştur düğmesine tıklayın ve bir bot adı ekleyin. Guilded sizi bot yapılandırma sayfasına yönlendirir.

  6. Bot yapılandırma sayfasındaki API bölümünü seçin.

  7. Jetonlar bölümünün altında, Jeton oluşturma düğmesine tıklayın.

  8. Oluşturulan jetonu güvenli bir dünyakaydedin ve saklayın.

Açık Bulut API anahtarı oluştur

Üçüncü taraf botunuzun kullanıcıların PII verilerini depolamak için veri depolarına erişmesine izin vermek için, deneyimlerinize erişebilen bir Açık Bulut API anahtarı oluşturun ve veri silme için veri depolarının Silme izni ekleyin izni ekleyin.Kişisel Tanıtıcı Bilgiler'yi depolamak için sıralı veri depoları kullanıyorsanız, sıralı veri depolarının Yazma iznini de eklemelisiniz.Bitirildikten sonra, API anahtarını daha sonraki adımlarda kullanmak için güvenli bir konumda kopyalayın ve kaydedin.

Deneyimlerin ve yerlerin tanımlayıcılarını alın

Bot'un, kullanıcılar tarafından silinmesi istenen PII verilerini bulması için, bot için kullanmayı planladığınız tüm deneyimlerin aşağıdaki tanımlarını alın:

  • The Evren ID , deneyiminizin benzersiz tanımlayıcısı.
  • The Başlangıç Yeri Kimliği , bir deneyimin başlangıç yerinin benzersiz tanımlayıcısı.

Bu tanımlayıcıları almak için:

  1. Navigate to the Yaratıcı Panosuna.

  2. Bir deneyimin küçük küçük resimüzerine gelin, düğmesine tıklayın ve ayrıca Evren ID'sini kopyala ve Başlangıç Yeri ID'sini kopyala seçin, birbirine göre.

Senaryoları ekleyin

Webhook, bot ve API anahtarını veri depoları için ayarladıktan sonra, botun otomasyon mantığını uygulayan senaryolara ekleyin.Aşağıdaki örnek Python 3'ü kullanır:

  1. Aşağıdaki komutları kullanarak Python kütüphaneleri yükle:

    Kütüphaneleri Yükle

    pip3 install guilded.py==1.8.0
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. Aynı dizinde bot mantığının farklı bölümlerine karşılık gelen aşağıdaki kodları kopyalayın ve kaydedin:

    bot_config.py

    BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # Başlangıç yeri ID'sine Sözlük to
    # (evren ID'si, (veri depoları adı, alanı ve giriş anahtarı listesi)) için
    # Standart Veri Depoları
    # Bu girişler altında depolanan kullanıcı verileri silinecek
    STANDARD_DATA_STORE_ENTRIES = {
    # Başlangıç ​​Konum Kimliği
    111111111: (
    # Evren ID'si
    222222222,
    [
    ("StandardDataStore1", "Scope1", "Key1_{user_id}"),
    ("StandardDataStore1", "Scope1", "Key2_{user_id}"),
    ("StandardDataStore2", "Scope1", "Key3_{user_id}")
    ]
    ),
    33333333: (
    444444444,
    [
    ("StandardDataStore3", "Scope1", "Key1_{user_id}")
    ]
    )
    }
    # Başlangıç yeri ID'sine Sözlük to
    # (evren ID'si, (veri depoları adı, alanı ve giriş anahtarı listesi)) için
    # Sıralanmış Veri Depoları
    # Bu girişler altında depolanan kullanıcı verileri silinecek
    ORDERED_DATA_STORE_ENTRIES = {
    111111111: (
    222222222,
    [
    ("OrderedDataStore1", "Scope2", "Key4_{user_id}")
    ]
    )
    }
    data_stores_api.py

    import requests
    import bot_config
    from collections import defaultdict
    """
    Calls Data Stores Open Cloud API to delete all entries for a user_id configured in
    STANDARD_DATA_STORE_ENTRIES. Returns a list of successful deletions and failures to delete.
    """
    def delete_standard_data_stores(user_id, start_place_ids):
    successes = defaultdict(list)
    failures = defaultdict(list)
    for owned_start_place_id in bot_config.STANDARD_DATA_STORE_ENTRIES:
    if owned_start_place_id not in start_place_ids:
    continue
    universe_id, universe_entries = bot_config.STANDARD_DATA_STORE_ENTRIES[owned_start_place_id]
    for (data_store_name, scope, entry_key) in universe_entries:
    entry_key = entry_key.replace("{user_id}", user_id)
    response = requests.delete(
    f"https://apis.roblox.com/datastores/v1/universes/{universe_id}/standard-datastores/datastore/entries/entry",
    headers={"x-api-key": bot_config.OPEN_CLOUD_API_KEY},
    params={
    "datastoreName": data_store_name,
    "scope": scope,
    "entryKey": entry_key
    }
    )
    if response.status_code in [200, 204]:
    successes[owned_start_place_id].append((data_store_name, scope, entry_key))
    else:
    failures[owned_start_place_id].append((data_store_name, scope, entry_key))
    return successes, failures
    """
    Calls Ordered Data Stores Open Cloud API to delete all entries for a user_id configured in
    ORDERED_DATA_STORE_ENTRIES. Returns a list of successful deletions and failures to delete.
    """
    def delete_ordered_data_stores(user_id, start_place_ids):
    successes = defaultdict(list)
    failures = defaultdict(list)
    for owned_start_place_id in bot_config.ORDERED_DATA_STORE_ENTRIES:
    if owned_start_place_id not in start_place_ids:
    continue
    universe_id, universe_entries = bot_config.ORDERED_DATA_STORE_ENTRIES[owned_start_place_id]
    for (data_store_name, scope, entry_key) in universe_entries:
    entry_key = entry_key.replace("{user_id}", user_id)
    response = requests.delete(
    f"https://apis.roblox.com/ordered-data-stores/v1/universes/{universe_id}/orderedDatastores/{data_store_name}/scopes/{scope}/entries/{entry_key}",
    headers={"x-api-key": bot_config.OPEN_CLOUD_API_KEY}
    )
    if response.status_code in [200, 204, 404]:
    successes[owned_start_place_id].append((data_store_name, scope, entry_key))
    else:
    failures[owned_start_place_id].append((data_store_name, scope, entry_key))
    return successes, failures
    message_parser.py

    import time
    import hmac
    import hashlib
    import re
    import base64
    import bot_config
    """
    Parses received message for Roblox signature and timestamp, the footer is only set if you
    configured webhook secret
    """
    def parse_footer(message):
    if not message.embeds[0].footer or \
    not message.embeds[0].footer.text:
    return "", 0
    footer_match = re.match(
    r"Roblox-Signature: (.*), Timestamp: (.*)",
    message.embeds[0].footer.text
    )
    if not footer_match:
    return "", 0
    else:
    signature = footer_match.group(1)
    timestamp = int(footer_match.group(2))
    return signature, timestamp
    """
    Verifies Roblox signature with configured secret to check for validity
    """
    def validate_signature(message, signature, timestamp):
    if not message or not signature or not timestamp:
    return False
    # 300 saniye içinde yeniden oynatma saldırısını engeller
    request_timestamp_ms = timestamp * 1000
    window_time_ms = 300 * 1000
    oldest_timestamp_allowed = round(time.time() * 1000) - window_time_ms
    if request_timestamp_ms < oldest_timestamp_allowed:
    return False
    # İmzayı doğrular
    timestamp_message = "{}.{}".format(timestamp, message.embeds[0].description)
    digest = hmac.new(
    bot_config.ROBLOX_WEBHOOK_SECRET.encode(),
    msg=timestamp_message.encode(),
    digestmod=hashlib.sha256
    ).digest()
    validated_signature = base64.b64encode(digest).decode()
    if signature != validated_signature:
    return False
    # Geçerli imza
    return True
    """
    Parses a received webhook messaged on Discord or Guilded. Extracts user ID, prevents replay attack
    based on timestamp received, and verifies Roblox signature with configured secret to check for
    validity.
    """
    def parse_message(message):
    # Kullanıcı kimliği ve oyun kimliği için alınan mesajı parçalar
    if len(message.embeds) != 1 or \
    not message.embeds[0].description:
    return "", []
    description_match = re.match(
    r"You have received a new notification for Right to Erasure for the User Id: (.*) in " +
    r"the game\(s\) with Ids: (.*)",
    message.embeds[0].description
    )
    if not description_match:
    return "", []
    user_id = description_match.group(1)
    start_place_ids = set(int(item.strip()) for item in description_match.group(2).split(","))
    signature, timestamp = parse_footer(message)
    if validate_signature(message, signature, timestamp):
    return user_id, start_place_ids
    else:
    return "", []
    guilded_bot.py

    import guilded
    import json
    import bot_config
    import data_stores_api
    import message_parser
    def run():
    client = guilded.Client()
    @client.event
    async def on_ready():
    print(f"{client.user} is listening to Right to Erasure messages")
    """
    Handler for webhook messages from Roblox
    """
    @client.event
    async def on_message(message):
    # mesajparçalar ve geçerli hale getirir
    user_id, start_place_ids = message_parser.parse_message(message)
    if not user_id or not start_place_ids:
    return
    # Standart veri depolama kullanıcı verilerini siler
    [successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Deleted standard data stores data for " +
    f"user ID: {user_id}, data: {dict(successes)}")
    if failures:
    await message.reply(f"Failed to delete standard data stores data for " +
    f"user ID: {user_id}, data: {dict(failures)}")
    # Sipariş edilmiş veri depoları kullanıcı verilerini siler
    [successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Deleted ordered data stores data for " +
    f"user ID: {user_id}, data: {dict(successes)}")
    if failures:
    await message.reply(f"Failed to delete ordered data stores data for " +
    f"user ID: {user_id}, data: {dict(failures)}")
    client.run(bot_config.BOT_TOKEN)
    if __name__ == "__main__":
    run()
  3. Botun ana yapılandırması için bot_config.py dosyasında:

    1. Botunuz tarafından üretilen jetona BOT_TOKEN ayarını verin.
    2. Yarattığınız API anahtarı olarak OPEN_CLOUD_API_KEY ayarlayın.
    3. Creator Dashboard'da webhook'u yapılandırırken ayarladığınız gizli ROBLOX_WEBHOOK_SECRET olarak ayarlayın.
    4. Her kaydın veri depolarını bulmak için STANDARD_DATA_STORE_ENTRIES ve ORDERED_DATA_STORE_ENTRIES sil:
      1. Kopyalanmış Başlangıç ​​Yeri Kimliklerini anahtar olarak ekleyin.
      2. Dizilim değerinin ilk elemanı olarak Evren Kimliklerini ekleyin.
      3. Dizinin ikinci elemanını veri depolarınızın adı, alanı, giriş anahtarı adı ve ilişkili Kullanıcı Kimliği ile değiştirin.Farklı bir veri şeması kullanıyorsanız, kendi veri şemanıza uygun olarak değiştirin.
  4. Botu çalıştırmak için aşağıdaki komutu yürütün:

    Guilded Bot'u çalıştır

    python3 guilded_bot.py
  5. Bot daha sonra silme İstekleri ve çağrıları için Roblox webhooklerini dinlemeye ve doğrulamaya başlar ve uygun veri mağazasilmek için Open Cloud uç noktasını çağırır.

Test

Özel programınızın doğru silme isteklerini ve PII verilerini düzgün bir şekilde ele alabileceğini doğrulamak için bir test mesajı oluşturup çalıştırabilirsiniz:

  1. Aşağıdaki istek vücutGuilded veya Discord webhook sunucunuza bir HTTP POST isteği gönderin:

    Örnek İstek

    curl -X POST {serverUrl}
    -H 'Content-Type: application/json'
    -d '{
    "embeds":[{
    "title":"RightToErasureRequest",
    "description":"You have received a new notification for Right to Erasure for the User Id: {userIds} in the game(s) with Ids: {gameIds}",
    "footer":{
    "icon_url":"https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png",
    "text":"Roblox-Signature: {robloxSignature}, Timestamp: {timestamp}"
    }
    }]
    }'
  2. Bir webhook sırrınız varsa:

    1. Webhook gizli anahtarınıza HMAC-SHA256 kodlaması uygulayarak bir Roblox-Signature oluşturun.
    2. UTC zaman damgasını kullanarak mevcut zamanı saniyeler içinde Timestamp olarak ayarlayın.
  3. Aşağıdaki formatla birleştir description :

    Description Field Format

    {Timestamp}. You have received a new notification for Right to Erasure for the User Id: {userId} in the game(s) with Ids: {gameIds}`.

    Örneğin:

    Example Description Field

    1683927229. You have received a new notification for Right to Erasure for the User Id: 2425654247 in the game(s) with Ids: 10539205763, 13260950955

Programınız, mesajınızın resmi Roblox kaynağından geldiğini tespit edebilmelidir, çünkü mesajı gizli ile kodladınız.Ardından, talepilişkili PII verilerini silmelidir.

Örnek Vücut

{
"embeds": [
{
"title": "RightToErasureRequest",
"description": "You have received a new notification for Right to Erasure for the User Id: 2425654247 in the game(s) with Ids: 10539205763, 13260950955",
"footer": {
"icon_url": "https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}