Automatyzacja wniosków o prawo do usunięcia danych

*Ta zawartość została przetłumaczona przy użyciu narzędzi AI (w wersji beta) i może zawierać błędy. Aby wyświetlić tę stronę w języku angielskim, kliknij tutaj.

Globalne przepisy dotyczące ochrony danych i prywatności dają jednostkom prawo do kontroli swoich danych, w tym prawo do żądania ich usunięcia (często określane jako "prawo do usunięcia" lub "prawo do skasowania"). Jeśli przechowujesz jakiekolwiek dane osobowe lub Dane Osobowe Identyfikowalne (PII), takie jak identyfikatory użytkowników, jesteś odpowiedzialny za przestrzeganie odpowiednich ram prywatności poprzez trwałe usunięcie tych informacji po otrzymaniu prośby od użytkownika. Więcej informacji można znaleźć w RTBF i twórcy.

Zamiast obsługiwać wnioski ręcznie, możesz ustawić webhook i użyć bota w aplikacji do przesyłania wiadomości trzeciej strony, aby zautomatyzować ten proces. Ponieważ bazy danych są najczęstszym sposobem przechowywania danych PII, ten samouczek przedstawia przykład, jak stworzyć bota w Discordzie, który wykorzystuje Open Cloud API dla baz danych do usuwania danych PII jako rozwiązania automatyzacyjnego.

Przepływ pracy

Po ukończeniu tego samouczka powinieneś być w stanie stworzyć lokalny program, który automatyzuje obsługę wniosków o prawo do usunięcia danych od użytkowników. Przepływ pracy w tym procesie przebiega następująco:

  1. Zespół wsparcia Roblox otrzymuje prośbę o prawo do usunięcia danych od użytkownika.
  2. Webhook Roblox jest wywoływany, zawierający identyfikator użytkownika oraz listę identyfikatorów miejsc startowych gier, w których uczestniczył, w ładunku.
  3. Twój bot nasłuchuje tych powiadomień webhook, weryfikując ich autentyczność, a następnie wykorzystuje Open Cloud API dla baz danych do usuwania danych PII przechowywanych w bazach danych.
  4. Bot odpowiada na wiadomość webhooka w Discordzie ze statusem usunięcia.

Skonfiguruj webhook z integracją zewnętrzną

Zanim stworzysz bota, skonfiguruj serwer z integracją webhook w aplikacji do przesyłania wiadomości trzeciej strony. Następnie użyj serwera do skonfigurowania webhooka na Creator Dashboard.

Ustaw serwer

Poniższe kroki pokazują, jak skonfigurować serwer przy użyciu Discorda.

  1. Stwórz nowy serwer Discord. Jeśli nie jesteś zaznajomiony z tym procesem, zobacz Wsparcie Discorda.

  2. Serwer automatycznie tworzy kanał #general jako domyślny. Kliknij ikonę Edytuj kanał w kanale #general.

  3. Pod Uprawnienia ustaw kanał na prywatny.

  4. Utwórz integrację webhook z nowym serwerem, nadając jej nazwę RTBF Hook. Jeśli nie jesteś zaznajomiony z tym procesem, zobacz Wsparcie Discorda.

  5. Skopiuj adres URL webhooka i przechowuj go w bezpiecznym miejscu. Pozwól tylko zaufanym członkom zespołu mieć do niego dostęp, ponieważ ujawnienie adresu URL może umożliwić niepożądanym osobom wysyłanie fałszywych wiadomości oraz potencjalne usunięcie twoich danych użytkowników.

Skonfiguruj webhooka w Robloxie

Po uzyskaniu adresu URL serwera zewnętrznego, użyj go do skonfigurowania webhooka na Creator Dashboard. upewnij się, że wykonujesz następujące ustawienia:

  • Dodaj adres URL serwera Discorda jako Webhook URL.
  • Dodaj niestandardowy Secret. Chociaż sekret jest opcjonalny do zakończenia konfiguracji, powinieneś go dodać, aby zapobiec podszywaniu się niepożądanych osób pod Roblox i usunięciu twoich danych. Aby uzyskać więcej informacji na temat użycia sekretu, zobacz Weryfikacja bezpieczeństwa webhooka.
  • Wybierz Wniosek o prawo do usunięcia pod Wyzwalacze.

Możesz przetestować webhook, używając przycisku Testuj odpowiedź, aby sprawdzić, czy otrzymujesz powiadomienie w kanale #general twojego serwera od Roblox. Jeśli nie otrzymasz powiadomienia, spróbuj ponownie lub sprawdź ustawienia swojego serwera, aby zdiagnozować błąd.

Skonfiguruj bota

Po dodaniu webhooka użyj go do skonfigurowania bota zgodnie z następującymi krokami. Aby uzyskać więcej informacji, zobacz dokumentację Discorda.

  1. Przejdź do strony aplikacji.
  2. Utwórz nową aplikację i nazwij ją RTBF Bot.
  3. System przekierowuje cię do ustawień Informacje ogólne bota. Skopiuj i zapisz jego identyfikator aplikacji w bezpiecznym miejscu.
  4. W menu ustawień wybierz OAuth2.
  5. Przejdź do ustawień OAuth2:
    1. Włącz zakres bot, a lista dodatkowych uprawnień bota zostanie wyświetlona.
    2. Dodaj uprawnienie Administrator. Zapisz swoje zmiany.
    3. Zapisz wygenerowany adres URL.
  6. Skopiuj wygenerowany adres URL. Nie zamykaj strony ustawień aplikacji.
  7. Przejdź do wygenerowanego adresu URL. Wybierz docelowy serwer. Kliknij przycisk Kontynuuj, a następnie przycisk Autoryzuj.
  8. Przejdź z powrotem do strony ustawień aplikacji i przejdź do ustawień bota.
  9. W sekcji Uprzywilejowane intencje bramy włącz Intencję treści wiadomości.
  10. W ustawieniach bota > sekcji Zbuduj bota zapisz token bota w bezpiecznym miejscu na późniejsze kroki. Jeśli nie widzisz tokena, kliknij przycisk Zresetuj token, aby wygenerować nowy.

Stwórz klucz API Open Cloud

Aby umożliwić twojemu botowi zewnętrznemu dostęp do twoich baz danych w celu przechowywania danych PII użytkowników, stwórz klucz API Open Cloud, który będzie miał dostęp do twoich gier i dodaj uprawnienie Usuń wpis baz danych w celu usunięcia danych. Jeśli używasz uporządkowanych baz danych do przechowywania PII, musisz również dodać uprawnienie Zapisz w uporządkowanych bazach danych. Po zakończeniu skopiuj i zapisz klucz API w bezpiecznym miejscu, aby użyć go w późniejszych krokach.

Uzyskaj identyfikatory gier i miejsc

Aby bot mógł zlokalizować dane PII żądane przez użytkowników do usunięcia, uzyskaj następujące identyfikatory wszystkich gier, dla których zamierzasz użyć bota:

  • ID Uniwersum, unikalny identyfikator twojej gry.
  • ID miejsca startowego, unikalny identyfikator miejsca startowego gry.

Aby uzyskać te identyfikatory:

  1. Przejdź do Creator Dashboard.

  2. Najedź na miniaturę gry, kliknij przycisk , a następnie wybierz Kopiuj ID uniwersum i Kopiuj ID miejsca startowego odpowiednio.

Dodaj skrypty

Po zakończeniu konfiguracji webhooka, bota i klucza API dla baz danych, dodaj je do skryptów implementujących logikę automatyzacji bota. Poniższy przykład używa Pythona 3.

  1. Zainstaluj biblioteki Pythona, używając następujących poleceń:

    Zainstaluj biblioteki
    pip3 install discord
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. Skopiuj i zapisz poniższe skrypty, odpowiadające różnym częściom logiki bota, w tym samym katalogu:

    bot_config.py
    BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # Słownik związku ID miejsca startowego z
    # (ID uniwersum, lista (nazwa bazy danych, zakres, i klucz wpisu)) dla
    # Standardowych Baz Danych
    # Dane użytkownika przechowywane pod tymi wpisami będą usunięte
    STANDARD_DATA_STORE_ENTRIES = {
    # ID miejsca startowego
    111111111: (
    # ID uniwersum
    222222222,
    [
    ("StandardDataStore1", "Scope1", "Key1_{user_id}"),
    ("StandardDataStore1", "Scope1", "Key2_{user_id}"),
    ("StandardDataStore2", "Scope1", "Key3_{user_id}")
    ]
    ),
    33333333: (
    444444444,
    [
    ("StandardDataStore3", "Scope1", "Key1_{user_id}")
    ]
    )
    }
    # Słownik związku ID miejsca startowego z
    # (ID uniwersum, lista (nazwa bazy danych, zakres, i klucz wpisu)) dla
    # Uporządkowanych Baz Danych
    # Dane użytkownika przechowywane pod tymi wpisami będą usunięte
    ORDERED_DATA_STORE_ENTRIES = {
    111111111: (
    222222222,
    [
    ("OrderedDataStore1", "Scope2", "Key4_{user_id}")
    ]
    )
    }
    data_stores_api.py
    import requests
    import bot_config
    from collections import defaultdict
    """
    Wywołuje Open Cloud API Baz Danych, aby usunąć wszystkie wpisy dla user_id skonfigurowanego w
    STANDARD_DATA_STORE_ENTRIES. Zwraca listę udanych usunięć oraz niepowodzeń w usunięciu.
    """
    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
    """
    Wywołuje Open Cloud API Uporządkowanych Baz Danych, aby usunąć wszystkie wpisy dla user_id skonfigurowanego w
    ORDERED_DATA_STORE_ENTRIES. Zwraca listę udanych usunięć oraz niepowodzeń w usunięciu.
    """
    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
    """
    Analizuje odebraną wiadomość, aby uzyskać podpis i znacznik czasu Roblox, stopka jest ustawiona tylko, jeśli
    skonfigurowano sekret webhook.
    """
    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
    """
    Weryfikuje podpis Roblox za pomocą skonfigurowanego sekretu, aby sprawdzić jego ważność
    """
    def validate_signature(message, signature, timestamp):
    if not message or not signature or not timestamp:
    return False
    # Zapobiega atakowi powtórzeniowemu w oknie 300 sekund
    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
    # Weryfikuje podpis
    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
    # Ważny podpis
    return True
    """
    Analizuje odebraną wiadomość webhook na Discordzie. Ekstrahuje ID użytkownika, zapobiega atakowi powtórzeniowemu
    na podstawie otrzymanego znacznika czasu i weryfikuje podpis Roblox za pomocą skonfigurowanego sekretu.
    """
    def parse_message(message):
    # Analizuje odebraną wiadomość w poszukiwaniu ID użytkownika i ID gry
    if len(message.embeds) != 1 or \
    not message.embeds[0].description:
    return "", []
    description_match = re.match(
    r"Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla ID Użytkownika: (.*) w " +
    r"grze(ach) z ID: (.*)",
    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 "", []
    discord_bot.py
    import discord
    import bot_config
    import data_stores_api
    import message_parser
    def run():
    intents = discord.Intents.default()
    intents.message_content = True
    client = discord.Client(intents=intents)
    @client.event
    async def on_ready():
    print(f"{client.user} nasłuchuje wiadomości o prawie do usunięcia danych")
    """
    Obsługuje wiadomości webhook od Roblox
    """
    @client.event
    async def on_message(message):
    # Analizuje i weryfikuje wiadomość
    user_id, start_place_ids = message_parser.parse_message(message)
    if not user_id or not start_place_ids:
    return
    # Usuwa dane użytkownika z standardowych baz danych
    [successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Usunięto dane użytkownika z standardowych baz danych dla " +
    f"ID użytkownika: {user_id}, dane: {dict(successes)}")
    if failures:
    await message.reply(f"Nie udało się usunąć danych użytkownika z standardowych baz danych dla " +
    f"ID użytkownika: {user_id}, dane: {dict(failures)}")
    # Usuwa dane użytkownika z uporządkowanych baz danych
    [successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Usunięto dane użytkownika z uporządkowanych baz danych dla " +
    f"ID użytkownika: {user_id}, dane: {dict(successes)}")
    if failures:
    await message.reply(f"Nie udało się usunąć danych użytkownika z uporządkowanych baz danych dla " +
    f"ID użytkownika: {user_id}, dane: {dict(failures)}")
    client.run(bot_config.BOT_TOKEN)
    if __name__ == "__main__":
    run()
  3. W pliku bot_config.py dla głównej konfiguracji bota:

    1. Ustaw BOT_TOKEN na token wygenerowany przez twój bot.
    2. Ustaw OPEN_CLOUD_API_KEY jako klucz API, który utworzyłeś.
    3. Ustaw ROBLOX_WEBHOOK_SECRET jako sekret, który ustawiłeś podczas konfigurowania webhooka w Creator Dashboard.
    4. W słownikach STANDARD_DATA_STORE_ENTRIES i ORDERED_DATA_STORE_ENTRIES, aby zlokalizować bazę danych każdego rekordu do usunięcia:
      1. Dodaj skopiowane ID miejsc startowych jako klucze.
      2. Dodaj ID uniwersum jako pierwszy element krotki.
      3. Zastąp drugi element krotki nazwą, zakresem, nazwą klucza wpisu oraz związanym ID użytkownika twoich baz danych. Jeśli używasz innej schematy danych, zmodyfikuj, aby odpowiadała twojej schematy danych.
  4. Wykonaj następujące polecenie, aby uruchomić bota:

    Uruchom bota Discord
    python3 discord_bot.py
  5. Bot zaczyna nasłuchiwać i weryfikować webhooki Roblox dla wniosków o prawo do usunięcia danych oraz wywołuje punkt końcowy Open Cloud w celu usunięcia odpowiednich danych z bazy danych.

Test

Możesz stworzyć i uruchomić testową wiadomość, aby zweryfikować, że twój program może poprawnie obsłużyć wnioski o prawo do usunięcia danych i usunąć dane PII:

  1. Wyślij żądanie HTTP POST do twojego serwera webhook Discord z następującym ciałem żądania:

    Przykładowe żądanie
    curl -X POST {serverUrl}
    -H 'Content-Type: application/json'
    -d '{
    "embeds":[{
    "title":"RightToErasureRequest",
    "description":"Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla ID Użytkownika: {userIds} w grze(grze) z ID: {gameIds}",
    "footer":{
    "icon_url":"https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png",
    "text":"Roblox-Signature: {robloxSignature}, Timestamp: {timestamp}"
    }
    }]
    }'
  2. Jeśli masz sekret webhook:

    1. Wygeneruj Roblox-Signature, stosując kodowanie HMAC-SHA256 do swojego klucza sekretu webhook.
    2. Ustaw aktualny czas, używając znaku czasu UTC w sekundach jako Timestamp.
  3. Złóż razem description w następującym formacie:

    Format pola opisu
    {Timestamp}. Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla ID Użytkownika: {userId} w grze(grze) z ID: {gameIds}`.

    Na przykład:

    Przykładowe pole opisu
    1683927229. Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla ID Użytkownika: 2425654247 w grze(grze) z ID: 10539205763, 13260950955

Twój program powinien być w stanie zidentyfikować, że twoja wiadomość pochodzi z oficjalnego źródła Roblox, ponieważ zakodowałeś wiadomość za pomocą swojego sekretu. Powinien następnie usunąć dane PII związane z twoim żądaniem.

Przykładowe ciało
{
"embeds": [
{
"title": "RightToErasureRequest",
"description": "Otrzymałeś nowe powiadomienie o prawie do usunięcia danych dla ID Użytkownika: 2425654247 w grze(grze) z ID: 10539205763, 13260950955",
"footer": {
"icon_url": "https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}
©2026 Roblox Corporation. Nazwa Roblox, logo Roblox oraz hasło „Powering Imagination” należą do naszych zarejestrowanych i niezarejestrowanych znaków towarowych na terenie Stanów Zjednoczonych oraz w innych krajach.