Automatizzare le richieste di cancellazione

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Il Regolamento generale sulla protezione dei dati (Informazioni di identificazione personale (PII)) è un regolamento europeo sulla protezione dei dati e sulla Privacy. Garanzie agli individui il diritto di richiedere la cancellazione dei loro dati personali, noti come il diritto all'oblio. Se memorizzi qualsiasi Informazione personalmente identificabile dei tuoi utenti, come i loro ID utente, devi conformart

Invece di gestire le richieste manualmente, puoi impostare un webhook e utilizzare un bot all'interno di un'applicazione di messaggi a terze parti per automatizzare il processo. Poiché i archivi di dati sono il modo più comune per archiviare i dati PII, questo tutorial fornisce un esempio su come creare un bot all'interno di Guilded o Discord che utilizza il

Flusso di lavoro

Al completamento di questo Tutoriale, dovresti essere in grado di creare un programma personalizzato in esecuzione localmente che automatizza il trattamento delle richieste di cancellazione dei utenti. Il flusso di lavoro per questo processo è come segue:

  1. Roblox Support riceve una richiesta di cancellazione di un utente.
  2. Il webhook Roblox viene attivato, contenendo l'ID utente e una lista di ID Start Place per le esperienze che hanno partecipato nel payload.
  3. Il tuo bot ascolta queste notifiche webhook, verifica la loro autenticità e utilizza il Open Cloud API for data stores per eliminare i dati PII memorizzati nei datastore.
  4. Il bot risponde al messaggio webhook in Discord o Guilded con lo Statodi eliminazione.

Configurazione di un Webhook con l'integrazione di terze parti

Prima di creare un bot, imposta un server con l'integrazione webhook sull'applicazione di messaggi di terze parti. Quindi usa il server per configurare un webhook sul Dashboard Creatore.

Configurazione di un server

I seguenti passaggi mostrano come configurare il server usando Guilded o Discord.

  1. Crea un nuovo ServerGuilded. Se non sei a conoscenza del processo, vedi Supporto Guilded.
  2. Sotto le impostazioni Privacy , imposta il server su Server privato. Il server crea automaticamente un canale privato #generico come canale predefinito.
  3. Crea un'integrazione con il webhook con il nuovo server e dargli un nome che puoi facilmente capire, come GDPR Hook. Se non sei a conoscenza del processo, vedi Supporto Guilded.
  4. Copia l'URL del webhook e memorizzalo in un Postosicuro. Consenti solo ai membri del team autorizzati ad accedervi, poiché il rilascio dell'URL può consentire agli attori non autorizzati di inviare messaggi falsi e potenzialmente eliminare i tuoi dati utente.

Configurazione di un Webhook su Roblox

Dopo aver ottenuto l'URL del server di terze parti, usalo per configurare un webhook sulla dashboard del creatore. assicurati di eseguire le seguenti impostazioni:

  • Aggiungi l'URL del server della gilda o Discord come URL del Webhook .
  • Includi un segreto personalizzato . Anche se un segreto è opzionale per completare la configurazione, dovresti includerlo per impedire agli attori malvagi di impersonare Roblox e eliminare i tuoi dati. Per ulteriori informazioni sull'uso di un segreto, vedi Verifica della sicurezza dell'Webhook.
  • Seleziona Richiesta di cancellazione della destra sotto Trigger .

Puoi testare il webhook utilizzando il pulsante Risposta di prova per vedere se ricevi una notifica nel tuo canale # generale da Roblox. Se non ricevi la Notifiche, prova di nuovo o controlla le impostazioni del tuo Serverper risolvere il problema.

Example notification on Guilded

Configurazione di un Bot

Dopo aver aggiunto il webhook, usalo per configurare il bot con i seguenti passaggi:

  1. Apri la lista Tutti i server facendo clic sull'icona o usando la Scorciatoia:

    • CtrlS su Windows.
    • S su Mac.
  2. Seleziona il tuo server per ricevere notifiche di cancellazione con il diritto di erasure.

  3. Espandi la lista sotto Server home e seleziona Gestisci bot .

  4. Il server crea automaticamente un canale privato # generale come canale predefinito.

  5. Fai clic sul pulsante Crea un bot e aggiungi un nome del bot. I guilded ti rimanda alla pagina di configurazione del bot.

  6. Seleziona la sezione API sulla pagina di configurazione del bot.

  7. Nella sezione Gettoni, fai clic sul pulsante Genera Token.

  8. Salva e memorizza il token generato in un Postosicuro.

Creazione di una Chiave dell'APIOpen Cloud

Per consentire al tuo bot di terze parti di accedere ai tuoi magazzini di dati per archiviare i dati PII degli utenti, crea una chiave API Open Cloud che può accedere alle tue esperienze e aggiungere il permesso Elimina modifica dei magazzini di dati per la cancellazione dei dati. Se usi magazzini di dati ordinati per archiviare i dati P

Ottenere ID delle esperienze e dei luoghi

Per il bot per localizzare i dati PII richiesti dagli utenti per la cancellazione, ottieni i seguenti identificatori di tutte le esperienze che intenzione di utilizzare il bot per:

  • Il ID Universe , l'identificatore unico della tua esperienza.
  • Il ID luogo di partenza ID , l'identificatore unico del luogo di partenza di un'esperienza.

Per ottenere questi identificatori, apri la pagina Creazioni su Dashboard del Creatore . Quindi seleziona un'esperienza e copia il ID Universe e 2>Start Place ID2> .

Copy Universe ID and Copy Start Place ID options from Creator Dashboard

Aggiungere script

Dopo aver finito di impostare il webhook, il bot e la chiave API per i dati, aggiungili agli script che implementano la logica di automazione del bot. Il seguente esempio usa Python 3:

  1. Installa librerie Python usando i seguenti comandi:

    Installare le librerie

    pip3 install discord
    pip3 install guilded.py==1.8.0
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. Copia e salva gli script seguenti corrispondenti a diverse parti della logica del bot nella stessa cartella:

    bot_config.py

    DISCORD_BOT_TOKEN = ""
    GUILDED_BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # Dizionario dell'ID del luogo di partenza per
    # (ID universo, elenco di (nome dei magazzini di dati, scala e chiave di accesso)) per
    # Store di dati standard
    # I dati dell'utente memorizzati sotto queste entrade verranno eliminati
    STANDARD_DATA_STORE_ENTRIES = {
    # ID luogo di partenza
    111111111: (
    # ID dell'Universo
    222222222,
    [
    ("StandardDataStore1", "Scope1", "Key1_{user_id}"),
    ("StandardDataStore1", "Scope1", "Key2_{user_id}"),
    ("StandardDataStore2", "Scope1", "Key3_{user_id}")
    ]
    ),
    33333333: (
    444444444,
    [
    ("StandardDataStore3", "Scope1", "Key1_{user_id}")
    ]
    )
    }
    # Dizionario dell'ID del luogo di partenza per
    # (ID universo, elenco di (nome dei magazzini di dati, scala e chiave di accesso)) per
    # Negozi di dati ordinati
    # I dati dell'utente memorizzati sotto queste entrade verranno eliminati
    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_ parsley

    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
    # Impedisce l'attacco di riproduzione entro la finestra di 300 secondi
    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
    # Firma con validità
    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
    # Firma valida
    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):
    # Parifica il messaggio per l'ID dell'utente e l'ID del gioco
    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):
    # Parsa e convalida il Messaggio
    user_id, start_place_ids = message_parser.parse_message(message)
    if not user_id or not start_place_ids:
    return
    # Elimina i dati di archiviazione standard memorizza i dati utente
    [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)}")
    # Elimina i dati memorizzati utente
    [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.GUILDED_BOT_TOKEN)
    if __name__ == "__main__":
    run()
  3. Nel file bot_config.py per la configurazione principale del bot:

    1. Imposta DISCORD_BOT_TOKEN o GUILDED_BOT_TOKEN sul token generato dal tuo bot.
    2. Imposta OPEN_CLOUD_API_KEY come la chiave API che hai creato.
    3. Imposta ROBLOX_WEBHOOK_SECRET come segreto che hai impostato quando hai configurato il webhook sulla dashboard del creatore.
    4. In STANDARD_DATA_STORE_ENTRIES e ORDERED_DATA_STORE_ENTRIES dizionari per localizzare il magazzino di dati di ciascun record da Eliminare:
      1. Aggiungi i tuoi ID di luogo di partenza copiati come chiavi.
      2. Aggiungi ID Universe come primo elemento del valore tupla.
      3. Rimpiazza il secondo elemento della lista con il nome, la scala, l'identificatore chiave e l'ID utente associato dei tuoi dati di archiviazione. Se usi un altro schema di dati, modifica per corrispondere al tuo stesso schema di dati in modo da poter essere utilizzato.
  4. Esegui il seguente comando per eseguire il bot:

    Esegui bot gildato

    python3 guilded_bot.py
  5. Il bot quindi inizia a ascoltare e verificare le richieste e gli errori dei webhook Roblox per il diritto di cancellazione e chiama l'endpoint Open Cloud per eliminare il relativo Negoziodi dati.

Testare

Puoi creare e eseguire un messaggio di test per verificare che il tuo programma personalizzato possa gestire correttamente le richieste di cancellazione e eliminare i dati PII:

  1. Invia una richiesta HTTP POST ai tuoi server di Guilded o Discord con il seguente corpo della richiesta:

    Richesta di esempio

    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. Se hai un webhook segreto:

    1. Genera una Roblox-Signature applicando l'encodazione HMAC-SHA256 alla tua chiave webhook segreta.
    2. Imposta l'ora corrente utilizzando il timestamp UTC in secondi come Timestamp .
  3. Metti insieme il description nel seguente formato:

    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}`.

    Ad esempio:

    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

Il tuo programma dovrebbe essere in grado di identificare che il tuo messaggio è dalla fonte ufficiale Roblox poiché hai incodificato il messaggio con il tuo segreto. Quindi dovrebbe eliminare i dati PII associati alla tua Richiesta.

Corpo di esempio

{
"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://creare.roblox.com/ashboard/asset/webhook/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}