Le normative globali sulla protezione dei dati e sulla privacy concedono agli individui il diritto di controllare i propri dati, incluso il diritto di richiederne la cancellazione (spesso definito come "diritto all'oblio" o "diritto di cancellazione"). Se memorizzi dati personali o Informazioni Personamente Identificabili (PII), come gli ID utente, sei responsabile della conformità ai relativi framework di privacy, eliminando permanentemente queste informazioni al ricevimento di una richiesta da parte dell'utente. Maggiori informazioni possono essere trovate in RTBF e creatori.
Considera alternative
Per i dati personali nei data store, l'opzione di automazione più semplice è configurare i modelli di cancellazione RTBF. Quando Roblox elabora una richiesta RTBF, elimina automaticamente le voci corrispondenti nei data store standard o ordinati senza richiedere di ospitare codice personalizzato. Per configurare i modelli e rivedere i modelli supportati, vedere Diritto all'oblio (RTBF) nei data store.
Il flusso di lavoro del webhook in questa pagina è utile quando:
- Memorizzi dati personali al di fuori dei data store.
- Il tuo schema di data store o caso d'uso non è supportato dai modelli di cancellazione RTBF.
- Hai bisogno di logica di elaborazione o cancellazione personalizzata.
Flusso di lavoro del webhook per creatori
Questo tutorial dimostra come configurare un webhook e creare un bot Discord in esecuzione localmente che utilizza l'Open Cloud API per i data store per automatizzare la gestione delle richieste di diritto all'oblio. Il flusso di lavoro per questo processo è il seguente:
- Il supporto Roblox riceve una richiesta di diritto all'oblio da un utente.
- Il webhook di Roblox viene attivato, contenente l'ID utente e un elenco di ID di Start Place per i giochi a cui hanno partecipato nel payload.
- Il tuo bot ascolta queste notifiche webhook, verifica la loro autenticità e utilizza l'Open Cloud API per i data store per eliminare i dati PII memorizzati nei data store.
- Il bot risponde al messaggio del webhook in Discord con lo stato della cancellazione.

Configura un webhook con integrazione di terze parti
Prima di creare un bot, configura un server con integrazione webhook sull'applicazione di messaggistica di terze parti. Quindi utilizza il server per configurare un webhook nel Creator Dashboard.
Configura un server
I seguenti passaggi mostrano come configurare il server utilizzando Discord.
Crea un nuovo server Discord. Se non sei familiare con il processo, consulta Supporto Discord.
Il server crea automaticamente un canale #general come canale predefinito. Fai clic sull'icona Modifica canale del canale #general.
Sotto Permessi, imposta il canale come privato.
Crea un'integrazione webhook con il nuovo server, chiamandola RTBF Hook. Se non sei familiare con il processo, consulta Supporto Discord.
Copia l'URL del webhook e conservalo in un luogo sicuro. Consenti solo ai membri fidati del team di accedervi, poiché la divulgazione dell'URL può consentire a soggetti malintenzionati di inviare messaggi falsi e potenzialmente eliminare i tuoi dati utente.
Configura un webhook su Roblox
Dopo aver ottenuto l'URL del server di terze parti, utilizzalo per configurare un webhook nel 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 facoltativo per completare la configurazione, dovresti includerne uno per prevenire che soggetti malintenzionati impersonino Roblox e cancellino 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 seguendo i seguenti passaggi. Per ulteriori informazioni, consulta la documentazione di Discord.
- Naviga alla pagina delle applicazioni.
- Crea una nuova applicazione e chiamala RTBF Bot.
- Il sistema ti reindirizza alle impostazioni di Informazioni generali del bot. Copia e salva il suo ID applicazione in un luogo sicuro.
- Sotto il menu delle impostazioni, seleziona OAuth2.
- Naviga alle impostazioni di OAuth2
- Abilita l'ambito bot, verrà visualizzato un elenco di ulteriori permessi per il bot.
- Aggiungi il permesso Amministratore. Salva le modifiche.
- Salva l'URL generato.
- Copia l'URL generato. Lascia aperta la pagina delle impostazioni dell'applicazione.
- Naviga all'URL generato. Seleziona il server di destinazione. Fai clic sul pulsante Continua e poi sul pulsante Autorizza.
- Torna alla pagina delle impostazioni dell'applicazione e naviga alle impostazioni del Bot.
- Nella sezione Intenzioni di gateway privilegiate, abilita Intento contenuto messaggi.
- Nelle impostazioni del Bot > sezione Build-A-Bot, salva il token del bot in un luogo sicuro per i passaggi successivi. Se non vedi il token, fai clic sul pulsante Reimposta 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 la cancellazione dei dati. Se utilizzi data store ordinati per memorizzare PII, devi anche aggiungere il permesso Scrivi dei data store ordinati. Dopo aver completato, copia e salva la chiave API in un luogo sicuro per utilizzarla nei passaggi successivi.
Ottieni identificatori di giochi e luoghi
Affinché il bot possa localizzare i dati PII richiesti dagli utenti per la cancellazione, ottieni i seguenti identificatori di tutti i giochi per i quali intendi utilizzare il bot:
- L'ID Universale, l'identificatore unico del tuo gioco.
- L'ID di Start Place, l'identificatore unico del luogo di partenza di un gioco.
Per ottenere questi identificatori:
Naviga al Creator Dashboard.
Passa sopra la miniatura di un gioco, fai clic sul pulsante ⋯ e seleziona Copia ID Universale e Copia ID di Start Place, 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.
Installa le librerie Python utilizzando i seguenti comandi:
Installa libreriepip3 install discordpip3 install requestspip3 install urllib3==1.26.6Copia e salva i seguenti script corrispondenti a diverse parti della logica del bot nella stessa directory:
bot_config.pyBOT_TOKEN = ""OPEN_CLOUD_API_KEY = ""ROBLOX_WEBHOOK_SECRET = ""# Dizionario dell'ID di Start Place 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 verranno eliminatiSTANDARD_DATA_STORE_ENTRIES = {# ID di Start Place111111111: (# ID Universale222222222,[("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 di Start Place 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 verranno eliminatiORDERED_DATA_STORE_ENTRIES = {111111111: (222222222,[("OrderedDataStore1", "Scope2", "Key4_{user_id}")])}data_stores_api.pyimport requestsimport bot_configfrom collections import defaultdict"""Chiama l'Open Cloud API dei Data Store per eliminare tutte le voci per un user_id configurato inSTANDARD_DATA_STORE_ENTRIES. Restituisce un elenco di cancellazioni riuscite e fallite."""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:continueuniverse_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'Open Cloud API dei Data Store Ordinati per eliminare tutte le voci per un user_id configurato inORDERED_DATA_STORE_ENTRIES. Restituisce un elenco di cancellazioni riuscite e fallite."""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:continueuniverse_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, failuresmessage_parser.pyimport timeimport hmacimport hashlibimport reimport base64import bot_config"""Analizza il messaggio ricevuto per la firma e il timestamp di Roblox, il footer è impostato solo se haiconfigurato il segreto del webhook"""def parse_footer(message):if not message.embeds[0].footer or \not message.embeds[0].footer.text:return "", 0footer_match = re.match(r"Roblox-Signature: (.*), Timestamp: (.*)",message.embeds[0].footer.text)if not footer_match:return "", 0else: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 ripetizione all'interno di una finestra di 300 secondirequest_timestamp_ms = timestamp * 1000window_time_ms = 300 * 1000oldest_timestamp_allowed = round(time.time() * 1000) - window_time_msif request_timestamp_ms < oldest_timestamp_allowed:return False# Valida la firmatimestamp_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 validareturn True"""Analizza un messaggio webhook ricevuto su Discord. Estrae l'ID utente, previene attacchi di ripetizionebasati 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 del giocoif 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_idselse:return "", []discord_bot.pyimport discordimport bot_configimport data_stores_apiimport message_parserdef run():intents = discord.Intents.default()intents.message_content = Trueclient = discord.Client(intents=intents)@client.eventasync def on_ready():print(f"{client.user} sta ascoltando i messaggi sul diritto all'oblio")"""Gestore per i messaggi webhook da Roblox"""@client.eventasync def on_message(message):# Analizza e valida il messaggiouser_id, start_place_ids = message_parser.parse_message(message)if not user_id or not start_place_ids:return# Elimina i dati utente dai data store standard[successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)if successes:await message.reply(f"Dati dei data store standard eliminati per " +f"ID utente: {user_id}, dati: {dict(successes)}")if failures:await message.reply(f"Impossibile eliminare i dati dei data store standard per " +f"ID utente: {user_id}, dati: {dict(failures)}")# Elimina i dati utente dai data store ordinati[successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)if successes:await message.reply(f"Dati dei data store ordinati eliminati per " +f"ID utente: {user_id}, dati: {dict(successes)}")if failures:await message.reply(f"Impossibile eliminare i dati dei data store ordinati per " +f"ID utente: {user_id}, dati: {dict(failures)}")client.run(bot_config.BOT_TOKEN)if __name__ == "__main__":run()Nel file bot_config.py per la configurazione principale del bot:
- Imposta BOT_TOKEN sul token generato dal tuo bot.
- Imposta OPEN_CLOUD_API_KEY come la chiave API che hai creato.
- Imposta ROBLOX_WEBHOOK_SECRET come il segreto che hai impostato quando hai configurato il webhook nel Creator Dashboard.
- Nei dizionari STANDARD_DATA_STORE_ENTRIES e ORDERED_DATA_STORE_ENTRIES per localizzare il data store di ciascun record da eliminare:
- Aggiungi i tuoi ID di Start Place copiati come chiavi.
- Aggiungi gli ID Universali come primo elemento della tupla valore.
- 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 di dati diverso, modifica per adattarlo al tuo schema di dati.
Esegui il seguente comando per avviare il bot:
Esegui il bot Discordpython3 discord_bot.pyIl bot inizia quindi 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:
Invia una richiesta HTTP POST al tuo server webhook Discord con il seguente corpo della richiesta:
Esempio di richiestacurl -X POST {serverUrl}-H 'Content-Type: application/json'-d '{"embeds":[{"title":"RichiestaDirittoAllOblio","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}"}}]}'Se hai un segreto webhook:
- Genera una Roblox-Signature applicando la codifica HMAC-SHA256 alla tua chiave segreta del webhook.
- Imposta l'ora corrente utilizzando il timestamp UTC in secondi come Timestamp.
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 di campo descrizione1683927229. 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.
{
"embeds": [
{
"title": "RichiestaDirittoAllOblio",
"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"
}
}
]
}