Automatizzare le richieste di diritto all'oblio

*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 (GDPR) è una normativa europea sulla protezione dei dati e sulla privacy. Esso concede agli individui il diritto di richiedere la cancellazione dei propri dati personali, noto come diritto all'oblio. Se memorizzi informazioni di identificazione personale (PII) dei tuoi utenti, come gli ID utente, devi rispettare i requisiti del GDPR eliminando queste informazioni al ricevimento di una richiesta da parte di un utente.

Invece di gestire le richieste manualmente, puoi impostare un webhook e utilizzare un bot all'interno di un'applicazione di messaggistica di terze parti per automatizzare il processo. Poiché i data store sono il modo più comune per memorizzare i dati PII, questo tutorial fornisce un esempio su come creare un bot all’interno di Discord che utilizza l'API Open Cloud per i data store per eliminare i dati PII come soluzione di automazione.

Flusso di lavoro

Al termine di questo tutorial, dovresti essere in grado di creare un programma personalizzato in esecuzione locale che automatizza la gestione delle richieste di diritto all'oblio da parte degli utenti. Il flusso di lavoro per questo processo è il seguente:

  1. Il supporto di Roblox riceve una richiesta di diritto all'oblio da un utente.
  2. Il webhook di Roblox viene attivato, contenente l'ID utente e un elenco di ID dei luoghi di avvio per i giochi ai quali hanno partecipato nel payload.
  3. Il tuo bot ascolta queste notifiche del webhook, verifica la loro autenticità e utilizza l'API Open Cloud per i data store per eliminare i dati PII memorizzati nei data store.
  4. Il bot risponde al messaggio del webhook in Discord con lo stato di eliminazione.

Configurare un webhook con integrazione di terze parti

Prima di creare un bot, imposta un server con integrazione webhook sull'applicazione di messaggistica di terze parti. Poi utilizza il server per configurare un webhook sul Creator Dashboard.

Imposta un server

I seguenti passi mostrano come impostare il server utilizzando Discord.

  1. Crea un nuovo server Discord. Se non sei familiare con il processo, consulta il Supporto Discord.

  2. Il server crea automaticamente un canale #general come tuo canale predefinito. Clicca sull'icona Modifica Canale del canale #general.

  3. Sotto Permessi, imposta il canale su privato.

  4. Crea un'integrazione webhook con il nuovo server, chiamalo GDPR Hook. Se non sei familiare con il processo, consulta il Supporto Discord.

  5. Copia l'URL del webhook e conservalo in un luogo sicuro. Consenti l'accesso solo ai membri affidabili del team, poiché la divulgazione dell'URL può consentire ad attori malevoli di inviare messaggi falsi e potenzialmente eliminare i dati dei tuoi utenti.

Configura un webhook su Roblox

Dopo aver ottenuto l'URL del server di terze parti, utilizzalo per configurare un webhook sul Creator Dashboard. Assicurati di eseguire le seguenti impostazioni:

  • Aggiungi l'URL del server Discord come Webhook URL.
  • Includi un Segreto personalizzato. Sebbene un segreto sia opzionale per completare la configurazione, dovresti includerne uno per prevenire che attori malevoli impersonino Roblox ed eliminino i tuoi dati. Per ulteriori informazioni sull'uso di un segreto, consulta Verifica della sicurezza del webhook.
  • Seleziona Richiesta di diritto all'oblio sotto Trigger.

Puoi testare il webhook utilizzando il pulsante Test Response per vedere se ricevi una notifica nel canale #general del tuo server da Roblox. Se non ricevi la notifica, riprova o controlla le impostazioni del tuo server per risolvere l'errore.

Configura un bot

Dopo aver aggiunto il webhook, utilizzalo per configurare il bot con i seguenti passi. Per ulteriori informazioni, consulta la documentazione di Discord.

  1. Crea una nuova applicazione e chiamala GDPR Bot.
  2. Il sistema ti reindirizza alle impostazioni di Informazioni Generali del bot. Copia e conserva il suo ID applicazione in un luogo sicuro.
  3. Sotto il menu delle impostazioni, seleziona OAuth2.
  4. Naviga alle impostazioni OAuth2
    1. Abilita l'ambito bot, si aprirà un elenco di autorizzazioni aggiuntive per il Bot.
    2. Aggiungi l'autorizzazione Amministratore. Salva le tue modifiche.
    3. Salva l'URL generato.
  5. Copia l'URL generato. Non chiudere la pagina delle impostazioni dell'applicazione.
  6. Naviga all'URL generato. Seleziona il server di destinazione. Clicca sul pulsante Continua e poi sul pulsante Autorizza.
  7. Torna alla pagina delle impostazioni dell'applicazione e vai alle impostazioni del Bot.
  8. Nella sezione Privileged Gateway Intents, abilita Message Content Intent.
  9. Nelle impostazioni del Bot > sezione Build-A-Bot, conserva il token del bot in un luogo sicuro per i passaggi successivi. Se non vedi il token, clicca sul pulsante Reset Token per generare uno nuovo.

Crea una chiave API Open Cloud

Per consentire al tuo bot di terze parti di accedere ai tuoi data store per memorizzare i dati PII degli utenti, crea una chiave API Open Cloud che possa accedere ai tuoi giochi e aggiungi il permesso Elimina voce dei data store per l'eliminazione dei dati. Se utilizzi data store ordinati per memorizzare i dati PII, devi anche aggiungere il permesso Scrivi dei data store ordinati. Al termine, copia e conserva la chiave API in un luogo sicuro per utilizzarla nei passaggi successivi.

Ottieni identificatori di giochi e luoghi

Affinché il bot localizzi i dati PII richiesti dagli utenti per l'eliminazione, ottieni i seguenti identificatori di tutti i giochi che intendi utilizzare per il bot:

  • L'ID Universale, l'identificatore unico del tuo gioco.
  • L'ID Luogo di Avvio, l'identificatore unico del luogo di avvio di un gioco.

Per ottenere questi identificatori:

  1. Naviga al Creator Dashboard.

  2. Passa sopra la miniatura di un gioco, clicca sul pulsante e seleziona Copia ID Universale e Copia ID Luogo di Avvio, rispettivamente.

Aggiungi script

Dopo aver completato la configurazione del webhook, del bot e della chiave API per i data store, aggiungili agli script che implementano la logica di automazione del bot. Il seguente esempio utilizza Python 3.

  1. Installa le librerie Python utilizzando i seguenti comandi:

    Installa Librerie

    pip3 install discord
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. Copia e conserva i seguenti script corrispondenti a diverse parti della logica del bot nella stessa directory:

    bot_config.py

    BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # Dizionario dell'ID Luogo di Avvio a
    # (ID universale, elenco di (nome dei data store, ambito e chiave di voce)) per
    # Data Store Standard
    # I dati utente memorizzati sotto queste voci saranno eliminati
    STANDARD_DATA_STORE_ENTRIES = {
    # ID Luogo di Avvio
    111111111: (
    # ID Universale
    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 Luogo di Avvio a
    # (ID universale, elenco di (nome dei data store, ambito e chiave di voce)) per
    # Data Store Ordinati
    # I dati utente memorizzati sotto queste voci saranno 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
    """
    Chiama l'API Open Cloud dei Data Store per eliminare tutte le voci per un user_id configurato in
    STANDARD_DATA_STORE_ENTRIES. Restituisce un elenco di eliminazioni riuscite e fallimenti di eliminazione.
    """
    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
    """
    Chiama l'API Open Cloud dei Data Store Ordinati per eliminare tutte le voci per un user_id configurato in
    ORDERED_DATA_STORE_ENTRIES. Restituisce un elenco di eliminazioni riuscite e fallimenti di eliminazione.
    """
    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
    """
    Analizza il messaggio ricevuto per la firma e il timestamp di Roblox, il piè di pagina è impostato solo se hai
    configurato il segreto del 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
    """
    Verifica la firma di Roblox con il segreto configurato per controllare la validità
    """
    def validate_signature(message, signature, timestamp):
    if not message or not signature or not timestamp:
    return False
    # Previene attacchi di replay all'interno di una 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
    # Valida la firma
    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
    """
    Analizza un messaggio webhook ricevuto su Discord. Estrae l'ID utente, previene attacchi di replay
    basati sul timestamp ricevuto e verifica la firma di Roblox con il segreto configurato per controllare la
    validità.
    """
    def parse_message(message):
    # Analizza il messaggio ricevuto per l'ID utente e l'ID gioco
    if len(message.embeds) != 1 or \
    not message.embeds[0].description:
    return "", []
    description_match = re.match(
    r"Hai ricevuto una nuova notifica per il diritto all'oblio per l'ID utente: (.*) nel " +
    r"gioco(i) con 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} sta ascoltando i messaggi di diritto all'oblio")
    """
    Gestore per i messaggi webhook da Roblox
    """
    @client.event
    async def on_message(message):
    # Analizza e verifica 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 degli utenti dei data store standard
    [successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Eliminati i dati dei data store standard per " +
    f"l'ID utente: {user_id}, dati: {dict(successes)}")
    if failures:
    await message.reply(f"Errore nell'eliminazione dei dati dei data store standard per " +
    f"l'ID utente: {user_id}, dati: {dict(failures)}")
    # Elimina i dati degli utenti dei data store ordinati
    [successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)
    if successes:
    await message.reply(f"Eliminati i dati dei data store ordinati per " +
    f"l'ID utente: {user_id}, dati: {dict(successes)}")
    if failures:
    await message.reply(f"Errore nell'eliminazione dei dati dei data store ordinati per " +
    f"l'ID utente: {user_id}, dati: {dict(failures)}")
    client.run(bot_config.BOT_TOKEN)
    if __name__ == "__main__":
    run()
  3. Nel file bot_config.py per la configurazione principale del bot:

    1. Imposta 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 il segreto che hai impostato quando configuravi il webhook sul Creator Dashboard.
    4. Nei dizionari STANDARD_DATA_STORE_ENTRIES e ORDERED_DATA_STORE_ENTRIES per localizzare il data store di ogni record da eliminare:
      1. Aggiungi i tuoi ID Luogo di Avvio copiati come chiavi.
      2. Aggiungi gli ID Universali come primo elemento della tupla valore.
      3. Sostituisci il secondo elemento della tupla con il nome, l'ambito, il nome della chiave di voce e l'ID utente associato dei tuoi data store. Se utilizzi uno schema dati diverso, modifica per corrispondere al tuo schema dati.
  4. Esegui il seguente comando per eseguire il bot:

    Esegui Bot Discord

    python3 discord_bot.py
  5. Il bot quindi inizia ad ascoltare e verificare i webhook di Roblox per le richieste di diritto all'oblio e chiama l'endpoint Open Cloud per eliminare il corrispondente data store.

Test

Puoi creare ed eseguire un messaggio di test per verificare che il tuo programma personalizzato possa gestire correttamente le richieste di diritto all'oblio e cancellare i dati PII:

  1. Invia una richiesta HTTP POST al tuo server webhook di Discord con il seguente corpo della richiesta:

    Esempio di Richiesta

    curl -X POST {serverUrl}
    -H 'Content-Type: application/json'
    -d '{
    "embeds":[{
    "title":"RichiestaDiDirittoAllOblio",
    "description":"Hai ricevuto una nuova notifica per il diritto all'oblio per l'ID utente: {userIds} nel gioco(i) con ID: {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 segreto webhook:

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

    Formato del Campo Descrizione

    {Timestamp}. Hai ricevuto una nuova notifica per il diritto all'oblio per l'ID utente: {userId} nel gioco(i) con ID: {gameIds}`.

    Ad esempio:

    Esempio Campo Descrizione

    1683927229. Hai ricevuto una nuova notifica per il diritto all'oblio per l'ID utente: 2425654247 nel gioco(i) con ID: 10539205763, 13260950955

Il tuo programma dovrebbe essere in grado di identificare che il tuo messaggio proviene dalla fonte ufficiale di Roblox poiché hai codificato il messaggio con il tuo segreto. Dovrebbe quindi eliminare i dati PII associati alla tua richiesta.

Esempio Corpo

{
"embeds": [
{
"title": "RichiestaDiDirittoAllOblio",
"description": "Hai ricevuto una nuova notifica per il diritto all'oblio per l'ID utente: 2425654247 nel gioco(i) con 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. Roblox, il logo Roblox e Powering Imagination sono tra i nostri marchi registrati e non registrati negli Stati Uniti. e altri paesi.