Automatizza le richieste di cancellazione giuste

*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 (RGPD) è un regolamento europeo sulla protezione dei dati e sulla Privacy.Garantisce agli individui il diritto di richiedere la cancellazione dei loro dati personali, noto come diritto all'oblio.Se memorizzi qualsiasi Informazione personalmente identificabile (Informazioni di identificazione personale (PII)) dei tuoi utenti, come i loro ID utente, devi rispettare i requisiti del GDPR eliminando tali informazioni al ricevimento della Richiestadi un utente.

Invece di gestire le richieste manualmente, puoi configurare un webhook e utilizzare un bot all'interno di un'applicazione di messaggi di terze parti per automatizzare il processo.Poiché i magazzini 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 l'Open Cloud API per i magazzini di dati per eliminare i dati PII come soluzione di automazione.

Flow di lavoro

Dopo aver completato questo Tutoriale, dovresti essere in grado di creare un programma personalizzato in esecuzione locale che automatizza la gestione delle richieste di cancellazione degli utenti.Il flusso di lavoro per questo processo è il seguente:

  1. Il supporto di Roblox riceve una richiesta di cancellazione da parte di un utente.
  2. Il webhook di Roblox viene attivato, contenendo l'ID utente e un elenco di ID di luogo di partenza per le esperienze a cui si sono unite nel payload.
  3. Il tuo bot ascolta queste notifiche di webhook, verifica la loro autenticità e utilizza l'Open Cloud API per i data store per eliminare i dati PII memorizzati nei data store.
  4. Il bot risponde al messaggio webhook in Discord o Guilded con lo Statodi eliminazione.

Configura un webhook con integrazione di terze parti

Prima di creare un bot, configura un server con integrazione di webhook sull'applicazione di messaggi di terze parti.Quindi usa il server per configurare un webhook sulla dashboard di Creator.

Configura un Server

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

  1. Crea un nuovo ServerGuilded. Se non sei familiare con il processo, vedi Supporto Guilded.
  2. Sotto le impostazioni Privacy , imposta il server in Server privato.Il server crea automaticamente un canale privato #generale come canale predefinito.
  3. Crea un'integrazione di webhook con il nuovo server e dagli un nome che puoi facilmente comprendere, come GDPR Hook .Se non sei familiarito con il processo, vedi Supporto Guilded.
  4. Copia l'URL del webhook e conservalo in un Postosicuro.Consenti solo ai membri del team fidati di accedervi, poiché perdere l'URL può abilitare gli attori cattivi a inviare messaggi falsi e potenzialmente eliminare i dati utente.

Configura un webhook su Roblox

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

  • Aggiungi l'URL del server Guilded o Discord come URL Webhook .
  • Includi un segreto personalizzato Segreto .Anche se un segreto è opzionale per completare la configurazione, dovresti includerne uno per impedire agli attori cattivi di impersonare Roblox e eliminare i tuoi dati.Per maggiori informazioni sull'uso di un segreto, vedi Verifica della sicurezza del webhook.
  • Seleziona Diritto alla richiesta di cancellazione sotto Trigger .

Puoi testare il webhook utilizzando il pulsante Risposta di prova per vedere se ricevi una notifica nel canale #generale del tuo Serverda Roblox.Se non ricevi la Notifiche, riprova o controlla le impostazioni del server per risolvere l'errore.

Example notification on Guilded

Configurare un bot

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

  1. Apri la lista di tutti i server cliccando sull'icona o usando il Scorciatoia:

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

  3. Espandi la lista sotto Home del server 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 di bot. Guilded ti reindirizza alla pagina di configurazione del bot.

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

  7. Nella sezione Token , clicca il pulsante Genera token .

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

Crea una chiave Open Cloud API

Per consentire al tuo bot di terze parti di accedere ai tuoi depositi di dati per memorizzare i dati PII degli utenti, crea una chiave Open Cloud API che può accedere alle tue esperienze e aggiungi il permesso Elimina entrata di depositi di dati per la cancellazione dei dati.Se utilizzi archivi dati ordinati per memorizzare Informazioni di identificazione personale (PII), devi anche aggiungere il permesso Scrivi degli archivi dati ordinati.Dopo la completamento, copia e salva la chiave API in una posizione sicura per utilizzarla in passi successivi.

Ottieni gli identificatori di esperienze e luoghi

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

  • L'ID Universo , l'identificatore univoco della tua esperienza.
  • L'ID luogo di inizio Start Place ID , l'identificatore univoco del luogo di inizio di un'esperienza.

Per ottenere questi identificatori:

  1. Naviga alla Dashboard del Creatore.

  2. Passa il mouse su una miniatura di un'esperienza, fai clic sul pulsante e seleziona Copia ID Universo e Copia ID luogo di partenza , rispettivamente.

Aggiungi script

Dopo aver configurato il webhook, il bot e la chiave API per i depositi di dati, aggiungili agli script che implementano la logica di automazione del bot.L'esempio seguente utilizza Python 3:

  1. Installa le librerie Python utilizzando i seguenti comandi:

    Installa biblioteche

    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 directory:

    bot_config.py

    BOT_TOKEN = ""
    OPEN_CLOUD_API_KEY = ""
    ROBLOX_WEBHOOK_SECRET = ""
    # Dictizione dell'ID del luogo di partenza a
    # (ID dell'universo, elenco di (nome del deposito di dati, scopo e chiave di ingresso)) per
    # Magazzini di dati standard
    # I dati utente memorizzati sotto queste voci 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}")
    ]
    )
    }
    # Dictizione dell'ID del luogo di partenza a
    # (ID dell'universo, elenco di (nome del deposito di dati, scopo e chiave di ingresso)) per
    # Magazzini di dati ordinati
    # I dati utente memorizzati sotto queste voci 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_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
    # Previene 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
    # Validifica 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
    """
    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):
    # Parses riceve il messaggio per l'ID 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 degli utenti dei depositi di dati standard
    [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 degli store di dati ordinati dell'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.BOT_TOKEN)
    if __name__ == "__main__":
    run()
  3. Sul file bot_config.py per la configurazione principale del bot:

    1. Imposta BOT_TOKEN al token generato dal tuo bot.
    2. Imposta OPEN_CLOUD_API_KEY come chiave API che hai creato.
    3. Imposta ROBLOX_WEBHOOK_SECRET come segreto che hai impostato quando hai configurato il webhook sulla dashboard di Creator.
    4. In STANDARD_DATA_STORE_ENTRIES e ORDERED_DATA_STORE_ENTRIES dizionari per localizzare il deposito di dati di ciascun record da Eliminare:
      1. Aggiungi i tuoi ID di luogo di partenza copiati come chiavi.
      2. Aggiungi gli ID dell'universo come primo elemento del valore tuple.
      3. Sostituisci il secondo elemento della tuple con il nome, la scala, il nome della chiave di ingresso e l'ID utente associato dei tuoi store di dati.Se usi uno schema di dati diverso, modifica per abbinare lo schema di dati proprio in modo appropriato.
  4. Esegui il seguente comando per eseguire il bot:

    Esegui il bot Guilded

    python3 guilded_bot.py
  5. Il bot quindi inizia a ascoltare e verificare i webhook di Roblox per i diritti di cancellazione delle richieste e chiama l'endpoint Open Cloud per la cancellazione del corrispondente Negoziodati.

Prova

Puoi creare e eseguire un messaggio di prova 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 al tuo server webhook Guilded o Discord con il seguente corpo della richiesta:

    Esempio di richiesta

    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 un Roblox-Signature applicando l'encoder HMAC-SHA256 alla tua chiave segreta del webhook.
    2. Imposta l'ora attuale utilizzando il timestamp UTC in secondi come Timestamp .
  3. Metti insieme il description in formato seguente:

    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 proviene dalla fonte ufficiale di Roblox poiché hai codificato 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/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}