Regulasi perlindungan data dan privasi global memberikan individu hak untuk mengontrol data mereka, termasuk hak untuk meminta penghapusannya (sering disebut sebagai "hak untuk penghapusan" atau "hak untuk menghapus"). Jika Anda menyimpan data pribadi atau Informasi yang Dapat Diidentifikasi Secara Pribadi (PII), seperti ID pengguna, Anda bertanggung jawab untuk mematuhi kerangka privasi yang berlaku dengan menghapus informasi ini secara permanen setelah menerima permintaan dari pengguna. Informasi lebih lanjut dapat ditemukan di RTBF dan kreator.
Pertimbangkan alternatif
Untuk data pribadi dalam penyimpanan data, opsi otomatisasi yang paling mudah adalah mengonfigurasi template penghapusan RTBF. Ketika Roblox memproses permintaan RTBF, ia secara otomatis menghapus entri penyimpanan data standar atau terurut yang cocok tanpa memerlukan Anda untuk menghosting kode kustom. Untuk mengonfigurasi template dan meninjau pola yang didukung, lihat Hak untuk dilupakan di penyimpanan data (RTBF).
Alur kerja webhook di halaman ini berguna ketika:
- Anda menyimpan data pribadi di luar penyimpanan data.
- Skema penyimpanan data Anda atau kasus penggunaan tidak didukung oleh template penghapusan RTBF.
- Anda memerlukan pemrosesan atau logika penghapusan kustom.
Alur kerja webhook kreator
Tutorial ini menunjukkan cara mengatur webhook dan membuat bot Discord yang berjalan secara lokal yang menggunakan Open Cloud API untuk penyimpanan data untuk mengotomatiskan penanganan permintaan hak untuk penghapusan. Alur kerja untuk proses ini adalah sebagai berikut:
- Dukungan Roblox menerima permintaan hak untuk penghapusan dari seorang pengguna.
- Webhook Roblox dipicu, berisi ID pengguna dan daftar ID Tempat Awal untuk permainan yang telah mereka ikuti dalam payload.
- Bot Anda mendengarkan notifikasi webhook ini, memverifikasi keasliannya, dan memanfaatkan Open Cloud API untuk penyimpanan data untuk menghapus data PII yang disimpan di penyimpanan data.
- Bot merespons pesan webhook di Discord dengan status penghapusan.

Konfigurasi webhook dengan integrasi pihak ketiga
Sebelum membuat bot, atur server dengan integrasi webhook di aplikasi pesan pihak ketiga. Kemudian gunakan server untuk mengonfigurasi webhook di Dasbor Kreator.
Atur server
Langkah-langkah berikut menunjukkan cara mengatur server menggunakan Discord.
Buat server Discord baru. Jika Anda tidak familiar dengan prosesnya, lihat Dukungan Discord.
Server secara otomatis membuat saluran #general sebagai saluran default Anda. Klik ikon Edit Channel dari saluran #general.
Di bawah Permissions, atur saluran menjadi pribadi.
Buat integrasi webhook dengan server baru, beri nama RTBF Hook. Jika Anda tidak familiar dengan prosesnya, lihat Dukungan Discord.
Salin URL webhook dan simpan di tempat yang aman. Hanya izinkan anggota tim yang tepercaya untuk mengaksesnya, karena membocorkan URL dapat memungkinkan aktor jahat mengirim pesan palsu dan berpotensi menghapus data pengguna Anda.
Konfigurasi webhook di Roblox
Setelah mendapatkan URL server pihak ketiga, gunakan untuk mengonfigurasi webhook di Dasbor Kreator. Pastikan Anda melakukan pengaturan berikut:
- Tambahkan URL server Discord sebagai Webhook URL.
- Sertakan Secret kustom. Meskipun secret bersifat opsional untuk menyelesaikan konfigurasi, Anda harus menyertakannya untuk mencegah aktor jahat menyamar sebagai Roblox dan menghapus data Anda. Untuk informasi lebih lanjut tentang penggunaan secret, lihat Verifikasi keamanan webhook.
- Pilih Permintaan Hak untuk Penghapusan di bawah Triggers.
Anda dapat menguji webhook menggunakan tombol Test Response untuk melihat apakah Anda menerima notifikasi di saluran #general server Anda dari Roblox. Jika Anda tidak menerima notifikasi, coba lagi atau periksa pengaturan server Anda untuk memecahkan kesalahan.
Konfigurasi bot
Setelah Anda menambahkan webhook, gunakan untuk mengonfigurasi bot dengan langkah-langkah berikut. Untuk informasi lebih lanjut, lihat dokumentasi Discord.
- Navigasikan ke halaman Aplikasi.
- Buat aplikasi baru dan beri nama RTBF Bot.
- Sistem akan mengarahkan Anda ke pengaturan Informasi Umum dari bot. Salin dan simpan ID aplikasi di tempat yang aman.
- Di bawah menu pengaturan, pilih OAuth2.
- Navigasikan ke pengaturan OAuth2
- Aktifkan ruang lingkup bot, daftar izin Bot tambahan akan ditampilkan.
- Tambahkan izin Administrator. Simpan perubahan Anda.
- Simpan URL yang dihasilkan.
- Salin URL yang dihasilkan. Biarkan halaman pengaturan aplikasi tidak ditutup.
- Navigasikan ke URL yang dihasilkan. Pilih server target. Klik tombol Continue dan kemudian tombol Authorize.
- Kembali ke halaman pengaturan aplikasi dan navigasikan ke pengaturan Bot.
- Di bawah bagian Privileged Gateway Intents, aktifkan Message Content Intent.
- Di pengaturan Bot > bagian Build-A-Bot, simpan token bot di tempat yang aman untuk langkah-langkah selanjutnya. Jika Anda tidak melihat token, klik tombol Reset Token untuk menghasilkan yang baru.
Buat kunci Open Cloud API
Untuk memungkinkan bot pihak ketiga Anda mengakses penyimpanan data Anda untuk menyimpan data PII pengguna, buat kunci Open Cloud API yang dapat mengakses permainan Anda dan tambahkan izin Hapus Entri dari penyimpanan data untuk penghapusan data. Jika Anda menggunakan penyimpanan data terurut untuk menyimpan PII, Anda juga perlu menambahkan izin Tulis dari penyimpanan data terurut. Setelah selesai, salin dan simpan kunci API di lokasi yang aman untuk digunakan di langkah-langkah selanjutnya.
Dapatkan pengidentifikasi permainan dan tempat
Agar bot dapat menemukan data PII yang diminta oleh pengguna untuk dihapus, dapatkan pengidentifikasi berikut dari semua permainan yang Anda maksudkan untuk digunakan bot:
- Universe ID, pengidentifikasi unik permainan Anda.
- Start Place ID, pengidentifikasi unik tempat awal dari sebuah permainan.
Untuk mendapatkan pengidentifikasi ini:
Navigasikan ke Dasbor Kreator.
Arahkan kursor ke thumbnail permainan, klik tombol ⋯, dan pilih Salin Universe ID dan Salin Start Place ID, masing-masing.

Tambahkan skrip
Setelah Anda selesai mengatur webhook, bot, dan kunci API untuk penyimpanan data, tambahkan mereka ke skrip yang menerapkan logika otomatisasi bot. Contoh berikut menggunakan Python 3.
Instal pustaka Python menggunakan perintah berikut:
Instal Pustakapip3 install discordpip3 install requestspip3 install urllib3==1.26.6Salin dan simpan skrip berikut yang sesuai dengan berbagai bagian logika bot di direktori yang sama:
bot_config.pyBOT_TOKEN = ""OPEN_CLOUD_API_KEY = ""ROBLOX_WEBHOOK_SECRET = ""# Kamus dari Start Place ID ke# (universe ID, daftar (nama penyimpanan data, scope, dan kunci entri)) untuk# Penyimpanan Data Standar# Data pengguna yang disimpan di bawah entri ini akan dihapusSTANDARD_DATA_STORE_ENTRIES = {# Start Place ID111111111: (# Universe ID222222222,[("StandardDataStore1", "Scope1", "Key1_{user_id}"),("StandardDataStore1", "Scope1", "Key2_{user_id}"),("StandardDataStore2", "Scope1", "Key3_{user_id}")]),33333333: (444444444,[("StandardDataStore3", "Scope1", "Key1_{user_id}")])}# Kamus dari Start Place ID ke# (universe ID, daftar (nama penyimpanan data, scope, dan kunci entri)) untuk# Penyimpanan Data Terurut# Data pengguna yang disimpan di bawah entri ini akan dihapusORDERED_DATA_STORE_ENTRIES = {111111111: (222222222,[("OrderedDataStore1", "Scope2", "Key4_{user_id}")])}data_stores_api.pyimport requestsimport bot_configfrom collections import defaultdict"""Memanggil Data Stores Open Cloud API untuk menghapus semua entri untuk user_id yang dikonfigurasi diSTANDARD_DATA_STORE_ENTRIES. Mengembalikan daftar penghapusan yang berhasil dan kegagalan untuk dihapus."""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"""Memanggil Ordered Data Stores Open Cloud API untuk menghapus semua entri untuk user_id yang dikonfigurasi diORDERED_DATA_STORE_ENTRIES. Mengembalikan daftar penghapusan yang berhasil dan kegagalan untuk dihapus."""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"""Mengurai pesan yang diterima untuk tanda tangan Roblox dan timestamp, footer hanya diatur jika Andamengonfigurasi secret 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"""Memverifikasi tanda tangan Roblox dengan secret yang dikonfigurasi untuk memeriksa kevalidan"""def validate_signature(message, signature, timestamp):if not message or not signature or not timestamp:return False# Mencegah serangan replay dalam jendela 300 detikrequest_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# Memvalidasi tanda tangantimestamp_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# Tanda tangan validreturn True"""Mengurai pesan webhook yang diterima di Discord. Mengekstrak ID pengguna, mencegah serangan replayberdasarkan timestamp yang diterima, dan memverifikasi tanda tangan Roblox dengan secret yang dikonfigurasi untuk memeriksakevalidan."""def parse_message(message):# Mengurai pesan yang diterima untuk ID pengguna dan ID permainanif 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_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} sedang mendengarkan pesan Hak untuk Penghapusan")"""Penangan untuk pesan webhook dari Roblox"""@client.eventasync def on_message(message):# Mengurai dan memvalidasi pesanuser_id, start_place_ids = message_parser.parse_message(message)if not user_id or not start_place_ids:return# Menghapus data pengguna penyimpanan data standar[successes, failures] = data_stores_api.delete_standard_data_stores(user_id, start_place_ids)if successes:await message.reply(f"Data penyimpanan data standar dihapus untuk " +f"ID pengguna: {user_id}, data: {dict(successes)}")if failures:await message.reply(f"Gagal menghapus data penyimpanan data standar untuk " +f"ID pengguna: {user_id}, data: {dict(failures)}")# Menghapus data pengguna penyimpanan data terurut[successes, failures] = data_stores_api.delete_ordered_data_stores(user_id, start_place_ids)if successes:await message.reply(f"Data penyimpanan data terurut dihapus untuk " +f"ID pengguna: {user_id}, data: {dict(successes)}")if failures:await message.reply(f"Gagal menghapus data penyimpanan data terurut untuk " +f"ID pengguna: {user_id}, data: {dict(failures)}")client.run(bot_config.BOT_TOKEN)if __name__ == "__main__":run()Di file bot_config.py untuk konfigurasi utama bot:
- Atur BOT_TOKEN ke token yang dihasilkan oleh bot Anda.
- Atur OPEN_CLOUD_API_KEY sebagai kunci API yang Anda buat.
- Atur ROBLOX_WEBHOOK_SECRET sebagai secret yang Anda atur saat mengonfigurasi webhook di Dasbor Kreator.
- Di kamus STANDARD_DATA_STORE_ENTRIES dan ORDERED_DATA_STORE_ENTRIES untuk menemukan penyimpanan data dari setiap catatan yang akan dihapus:
- Tambahkan Start Place ID yang Anda salin sebagai kunci.
- Tambahkan Universe ID sebagai elemen pertama dari nilai tuple.
- Ganti elemen kedua dari tuple dengan nama, scope, nama kunci entri, dan ID Pengguna yang terkait dengan penyimpanan data Anda. Jika Anda menggunakan skema data yang berbeda, modifikasi untuk mencocokkan skema data Anda sendiri.
Jalankan perintah berikut untuk menjalankan bot:
Jalankan Bot Discordpython3 discord_bot.pyBot kemudian mulai mendengarkan dan memverifikasi webhook Roblox untuk permintaan hak untuk penghapusan dan memanggil endpoint Open Cloud untuk menghapus penyimpanan data yang sesuai.
Uji
Anda dapat membuat dan menjalankan pesan uji untuk memverifikasi bahwa program kustom Anda dapat menangani permintaan hak untuk penghapusan dengan benar dan menghapus data PII:
Kirim permintaan HTTP POST ke server webhook Discord Anda dengan body permintaan berikut:
Contoh Permintaancurl -X POST {serverUrl}-H 'Content-Type: application/json'-d '{"embeds":[{"title":"RightToErasureRequest","description":"Anda telah menerima notifikasi baru untuk Hak untuk Penghapusan untuk ID Pengguna: {userIds} di permainan dengan ID: {gameIds}","footer":{"icon_url":"https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png","text":"Roblox-Signature: {robloxSignature}, Timestamp: {timestamp}"}}]}'Jika Anda memiliki secret webhook:
- Hasilkan Roblox-Signature dengan menerapkan pengkodean HMAC-SHA256 pada kunci secret webhook Anda.
- Atur waktu saat ini menggunakan timestamp UTC dalam detik sebagai Timestamp.
Susun description dalam format berikut:
Format Field Deskripsi{Timestamp}. Anda telah menerima notifikasi baru untuk Hak untuk Penghapusan untuk ID Pengguna: {userId} di permainan dengan ID: {gameIds}`.Sebagai contoh:
Contoh Field Deskripsi1683927229. Anda telah menerima notifikasi baru untuk Hak untuk Penghapusan untuk ID Pengguna: 2425654247 di permainan dengan ID: 10539205763, 13260950955
Program Anda harus dapat mengidentifikasi bahwa pesan Anda berasal dari sumber resmi Roblox karena Anda telah mengenkripsi pesan dengan secret Anda. Ini harus kemudian menghapus data PII yang terkait dengan permintaan Anda.
{
"embeds": [
{
"title": "RightToErasureRequest",
"description": "Anda telah menerima notifikasi baru untuk Hak untuk Penghapusan untuk ID Pengguna: 2425654247 di permainan dengan ID: 10539205763, 13260950955",
"footer": {
"icon_url": "https://create.roblox.com/dashboard/assets/webhooks/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}