Undang-undang Perlindungan Data Umum (GDPR) adalah undang-undang Eropa tentang perlindungan data dan privasi. Ini memberi individu hak untuk meminta penghapusan data pribadi mereka, yang dikenal sebagai hak untuk menghapus. Jika Anda menyimpan setiap Informasi Pribadi yang Dapat Dipeng
Alih-alih menangani permintaan secara manual, Anda dapat mengatur panggilan webhook dan menggunakan bot dalam aplikasi pesan lain untuk secara otomatis mengotomatisasi proses ini. Karena simpan data adalah cara paling umum untuk menyimpan data PII, tutorial ini memberikan contoh tentang cara mengatur bot dalam Guild
Alur kerja
Setelah menyelesaikan tutorial ini, Anda harus dapat membuat program khusus yang berjalan lokal yang secara otomatis menangani permintaan hak penghapusan dari pengguna. Flow kerja untuk proses ini sebagai berikut:
- Dukungan Roblox menerima permintaan penghapusan dari pengguna.
- Pelat Salib Roblox diaktifkan, berisi ID Pengguna dan daftar Start Place ID untuk pengalaman yang mereka bergabung dalam payload.
- Bot Anda mendengarkan notifikasi webhook ini, memverifikasi keaslian mereka, dan menggunakan Open Cloud API for data stores untuk menghapus data PII yang disimpan di data store.
- Bot menanggapi pesan webhook di Discord atau Guilded dengan status penghapusan.
Mengkonfigurasi Webhook dengan Integrasi Pihak Ketiga
Sebelum menciptakan bot, konfigurasikan server dengan integrasi webhook di aplikasi pesan pihak ketiga. Kemudian gunakan server untuk mengkonfigurasi webhook di Dasbor Kreator.
Mengatur Server
Langkah-langkah berikut menunjukkan cara mengatur server menggunakan Guilded atau Discord.
- Buat server Guilded baru. Jika Anda tidak familiar dengan prosesnya, lihat Dukungan Guilded.
- Di bawah pengaturan Privasi , server diatur menjadi privat. Server secara otomatis membuat saluran pribadi #general sebagai channeldefault Anda.
- Buat integrasi webhook dengan server baru dan beri nama yang mudah Anda mengerti, seperti GDPR Hook. Jika Anda tidak familiar dengan proses ini, lihat Dukungan Guilded.
- Kopi URL webhook dan simpan di tempat yang aman. Hanya memungkinkan anggota tim yang dipercaya untuk mengaksesnya, karena menyebarkan URL dapat mengaktifkan aktor jahat untuk mengirim pesan palsu dan potensialmente menghapus data pengguna Anda.
Mengkonfigurasi Webhook di Roblox
Setelah mendapatkan URL server pihak ketiga, gunakan itu untuk konfigurasikan webhook di Dasbor Kreator. pastikan Anda melakukan pengaturan berikut:
- Tambahkan URL server Guilded atau Discord sebagai URL Webhook .
- Masukkan Rahasia khusus . Meskipun rahasia adalah pilihan untuk menyelesaikan konfigurasi, Anda harus meng包括 satu untuk mencegah aktor jahat menyamar Roblox dan menghapus data Anda. Untuk lebih banyak informasi tentang penggunaan rahasia, lihat Verifying Webhook Security.
- Pilih Hak Hapus Permintaan di bawah Trigger .
Anda dapat menguji webhook menggunakan tombol Tester Balasan untuk melihat apakah Anda menerima notifikasi di saluran # general Roblox Anda. Jika Anda tidak menerima notifikasi, coba lagi atau periksa pengaturan server Anda untuk menyelesaikan masalah.
Mengkonfigurasi Bot
Setelah menambahkan webhook, gunakan itu untuk mengkonfigurasi bot dengan langkah berikut:
Buka daftar Semua server dengan mengklik ikonnya atau gunakan pintasan cepat:
- CtrlS di Windows.
- ⌘S di Mac.
Pilih server Anda untuk menerima pengingat pemusnahan.
Jadilah daftar di bawah Beranda server dan pilih Manage Bots .
Server secara otomatis membuat saluran pribadi # general sebagai channeldefault Anda.
Klik tombol Buat Bot dan tambahkan nama bot. Guilded mengalihkan Anda ke halaman konfigurasi bot.
Pilih bagian API di halaman konfigurasi bot.
Di bawah bagian Token , klik tombol Menghasilkan Token .
Simpan dan toko token yang dihasilkan di tempat yang aman.
Menciptakan Kunci API Cloud Open
Untuk memungkinkan bot pihak ketiga Anda untuk mengakses toko data Anda untuk menyimpan data PII pengguna, buat kunci Open Cloud API yang dapat mengakses pengalaman Anda dan menambahkan izin Menghapus Entri dari toko data untuk menyimpan data. Jika Anda menggunakan toko data y
Mendapatkan Identifier Pengalaman dan Tempat
Untuk membantu bot menemukan data PII yang diminta pengguna untuk dihapus, dapatkan identifikasi berikut dari semua pengalaman yang Anda niatkan untuk menggunakan bot untuk:
- ID Alam Semesta, identifikator unik pengalaman Anda.
- The Start Place ID , identitas unik dari tempat awal pengalaman.
Untuk mendapatkan identitas ini, buka halaman Karya di Dashboard Pencipta. Kemudian pilih pengalaman dan salinan ID Universe dan 2>Start Place ID2>.
Menambahkan Skrip
Setelah Anda selesai mengatur webhook, bot, dan kunci API untuk penyimpanan data, tambahkan mereka ke skrip yang meng implementasikan logika otomatisasi bot. Contoh berikut menggunakan Python 3:
Instal library Python menggunakan perintah berikut:
Pasang Perpustakaanpip3 install discordpip3 install guilded.py==1.8.0pip3 install requestspip3 install urllib3==1.26.6Kopi dan simpan skrip berikut yang sesuai dengan berbagai bagian logika bot di direktori yang sama:
bot_konfigurasi.pyDISCORD_BOT_TOKEN = ""GUILDED_BOT_TOKEN = ""OPEN_CLOUD_API_KEY = ""ROBLOX_WEBHOOK_SECRET = ""# Daftar Start place ID untuk# (ID alam semesta, daftar (nama toko data, skala, dan kunci unit)) untuk# Toko Data Standar# Data pengguna yang disimpan di bawah entri ini akan dihapusSTANDARD_DATA_STORE_ENTRIES = {# ID Tempat Mulai111111111: (# ID Universe222222222,[("StandardDataStore1", "Scope1", "Key1_{user_id}"),("StandardDataStore1", "Scope1", "Key2_{user_id}"),("StandardDataStore2", "Scope1", "Key3_{user_id}")]),33333333: (444444444,[("StandardDataStore3", "Scope1", "Key1_{user_id}")])}# Daftar Start place ID untuk# (ID alam semesta, daftar (nama toko data, skala, dan kunci unit)) untuk# Toko Data yang Dipesan# Data pengguna yang disimpan di bawah entri ini akan dihapusORDERED_DATA_STORE_ENTRIES = {111111111: (222222222,[("OrderedDataStore1", "Scope2", "Key4_{user_id}")])}数据_存储_api.pyimport requestsimport bot_configfrom collections import defaultdict"""Calls Data Stores Open Cloud API to delete all entries for a user_id configured inSTANDARD_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: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"""Calls Ordered Data Stores Open Cloud API to delete all entries for a user_id configured inORDERED_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: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, failurespesan_sisip.pyimport timeimport hmacimport hashlibimport reimport base64import bot_config"""Parses received message for Roblox signature and timestamp, the footer is only set if youconfigured webhook secret"""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"""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# Mencegah serangan ulang dalam jendela waktu 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# Mengaktifkan tanda tanganitimestamp_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 tangani yang validreturn True"""Parses a received webhook messaged on Discord or Guilded. Extracts user ID, prevents replay attackbased on timestamp received, and verifies Roblox signature with configured secret to check forvalidity."""def parse_message(message):# Menerima pesan 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 "", []guilded_bot.pyimport guildedimport jsonimport bot_configimport data_stores_apiimport message_parserdef run():client = guilded.Client()@client.eventasync def on_ready():print(f"{client.user} is listening to Right to Erasure messages")"""Handler for webhook messages from Roblox"""@client.eventasync def on_message(message):# Mengambil dan menyediakan pesanuser_id, start_place_ids = message_parser.parse_message(message)if not user_id or not start_place_ids:return# Menghapus data pengguna toko data standar[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)}")# Menghapus data yang dipesan menyimpan data pengguna[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()Pada file bot_config.py untuk konfigurasi utama bot:
- Tetapkan DISCORD_BOT_TOKEN atau GUILDED_BOT_TOKEN ke token yang dihasilkan oleh bot Anda.
- Tetapkan OPEN_CLOUD_API_KEY sebagai kunci API yang Anda buat.
- Tetapkan ROBLOX_WEBHOOK_SECRET sebagai rahasia yang Anda tetapkan saat mengkonfigurasi webhook di Dasbor Kreator.
- Di STANDARD_DATA_STORE_ENTRIES dan ORDERED_DATA_STORE_ENTRIES典典 untuk menemukan data store masing-masing catatan untuk dihapus:
- Tambahkan Start Place ID Anda sebagai kunci.
- Tambahkan ID Universe sebagai elemen pertama dari nilai tuple.
- Ganti elemen kedua dari tuple dengan nama, scope, nama kunci entri, dan User ID yang terkait dari data store Anda. Jika Anda menggunakan schema data yang berbeda, modifikasi untuk menyesuaikan data script Anda sesuai.
Jalankan perintah berikut untuk mengeksekusi bot:
Jalankan Bot Guildedpython3 guilded_bot.pyBot kemudian mulai mendengarkan dan memverifikasi Roblox webhook untuk hak menghapus permintaan dan panggilan Open Cloud untuk menghapus data yang sesuai.
Menguji
Anda dapat menciptakan dan mengeksekui pesan pengujian untuk memverifikasi bahwa program khusus Anda dapat menangani permintaan hak akses dengan benar dan menghapus data PII:
Kirim permintaan HTTP POST ke server webhook Guilded atau Discord Anda dengan tubuhpermintaan berikut:
Permintaan Contohcurl -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}"}}]}'Jika Anda memiliki webhook rahasia:
- Hasilkan Roblox-Signature dengan menerapkan unitenkripsi HMAC-SHA256 ke kunci webhook rahasia Anda.
- Tetapkan waktu saat ini menggunakan UTC timestamp dalam detik sebagai Timestamp .
Gabungkan description dalam format berikut:
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}`.Sebagai contoh:
Example Description Field1683927229. You have received a new notification for Right to Erasure for the User Id: 2425654247 in the game(s) with Ids: 10539205763, 13260950955
Program Anda harus dapat mengidentifikasi bahwa pesan Anda berasal dari sumber Roblox resmi karena Anda telah men-Encoding pesan dengan rahasia Anda. Itu kemudian harus menghapus data PII yang terkait dengan permintaan Anda.
Contoh Tubuh
{
"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://create.roblox.com/ashboard/asset/webhook/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}