ความเป็นส่วนตัว(GDPR) เป็นกฎหมายการคุ้มครองข้อมูลส่วนบุคคลของยุโรป มันให้สิทธิให้ผู้ใช้ร้องขอให้ข้อมูลส่ว
แทนที่จะจัดการคำขอด้วยมือโดยใช้คำขอแบบเรียกแห่งเวลา คุณสามารถ ติดตั้งปลั๊กอินเว็บhook และใช้บอทในแอปพลิเคชันของบุคคลที
กระบวนการ
เมื่อเสร็จสิ้นการดูแลตัวอักษรในวิดีโอนี้คุณควรสามารถสร้างโปรแกรมที่ดำเนินการในพื้นที่เดียวที่จัดการการจัดการของตัวอักษรโดยอัตโนมัติจากผู้ใช้ กระบวนการนี้เป็นด้วยวิธีต่อไปนี้:
- Roblox Support ได้รับสิทธิ์ในการลบข้อมูลจากผู้ใช้
- เว็บไซต์ของ Roblox จะถูกเรียกใช้ โดยมี User ID และรายการ Start Place IDs สำหรับประสบการณ์ที่พวกเขาเข้าร่วมในโหลด
- บอทของคุณฟังสำหรับการแจ้งเตือนเหล่านี้ของ webhook ตรวจสอบความถูกต้องของพวกเขาและใช้ เปิด API เมฆสำหรับคลังข้อมูลเพื่อเก็บข้อมูลในคลังข้อมูล เพื่อลบข้อมูล PII ที่เก็บไว้ในคลังข้อมูล
- บอทตอบสนองต่อข้อความ webhook ใน Discord หรือ Guilded ด้วยสถานะการลบ
การกำหนดค่า Webhook ด้วยการผสานของบุคคลที่สาม
ก่อนสร้างบอทให้ตั้งค่าเซิร์ฟเวอร์ด้วยการใช้งาน webhook บนแอปพลิเคชันการส่งข้อความระหว่างผู้สร้างกับผู้ใช้ จากนั้นใช้เซิร์ฟเวอร์เพื่อกำหนด webhook ใน Dashboard ของผู้สร้าง
การติดตั้งเซิร์ฟเวอร์
ขั้นตอนต่อไปแสดงให้เห็นวิธีการติดตั้งเซิร์ฟเวอร์โดยใช้ Guilded หรือ Discord
- สร้างเซิร์ฟเวอร์ใหม่ หากคุณไม่คุ้นเคยกับกระบวนการนี้ให้ดู การสนับสนุนแบบกิลด์
- ภายใต้การตั้งค่า ความเป็นส่วนตัว ให้เซิร์ฟเวอร์เป็นส่วนตัว เซิร์ฟเวอร์จะสร้างช่อง # ส่วนตัวโดยอัตโนมัติเป็นช่องเริ่มต้นของคุณ
- สร้างการผสาน webhook กับเซิร์ฟเวอร์ใหม่และให้ชื่อที่คุณสามารถเข้าใจได้อย่างง่ายดายเช่น GDPR Hook หากคุณไม่คุ้นเคยกับกระบวนการนี้ให้ดู การสนับสนุนของกิลด์
- คัดลอก URL ของ webhook และเก็บไว้ในสถานที่ที่ปลอดภัย อนุญาตให้สมาชิกทีมที่ไว้วางใจเท่านั้นที่เข้าถึงได้ เนื่องจากการเปิดเผย URL สามารถเปิดเผยข้อความปลอมและอาจลบข้อมูลผู้ใช้ของคุณ
การกำหนดค่า Webhook บน Roblox
หลังจากได้รับ URL ของเซิร์ฟเวอร์บุคคลที่สาม, ใช้มันเพื่อ กำหนดเวลาเรื่องกิจกรรมของเว็บไซต์ ใน แดชบอร์ดครีเอเตอร์โปรดทำตามการตั้งค่าต่อไปนี้:
- เพิ่ม URL เซิร์ฟเวอร์ Guilded หรือ Discord เป็น URL เว็บของของเรา * รวมถึงรหัสลับ ที่ซ่อนอยู่ แม้ว่ารหัสลับจะเป็นตัวเลือกสำหรับการเสร็จสิ้นการกำหนดค่า แต่คุณควรรวมอย่างน้อยหนึ่งรหัสเพื่อป้องกันการปลอมตัวของ Roblox และการลบข้อมูล
- เลือก สิทธิ์ในการลบข้อมูลของฉัน ภายใต้ การเรียกร้องของการลบข้อมูล คุณสามารถทดสอบข้อมูลเกี่ยวกับเว็บไซต์ของคุณโดยใช้ปุ่ม ตอบกลับการทดสอบ เพื่อดูว่าคุณจะได้รับการแจ้งเตือนในช่อง # general ของเซิร์ฟเวอร์จาก Roblox หากคุณไม่ได้รับก
การกำหนดตัวบอท
หลังจากเพิ่มตัวแปร webhook ให้ใช้มันเพื่อกำหนดบอทด้วยขั้นตอนต่อไปนี้:
เปิดรายการ เซิร์ฟเวอร์ทั้งหมด โดยการคลิกไอคอนของมันหรือใช้ทางลัด:
- CtrlS บน Windows
- ⌘S บน Mac
เลือกเซิร์ฟเวอร์ของคุณเพื่อรับการแจ้งเตือนเมื่อถูกลบ
ขยายรายการใต้ หน้าเวิร์เตอร์ และเลือก จัดการบอท
เซิร์ฟเวอร์จะสร้างช่อง # general เป็นช่องปกติของคุณโดยอัตโนมัติ
คลิกปุ่ม สร้างบอท และเพิ่มชื่อบอท ปุ่มนี้จะเปลี่ยนคุณเป็นเซิร์ฟเวอร์บอทที่การีนามคุณไปยังหน้าการกำหนดค่าบอท
เลือกส่วน API บนหน้าการกำหนดค่าบอท
ในส่วน โทเค็น คลิกปุ่ม สร้างโทเค็น
บันทึกและเก็บตั๋วที่สร้างขึ้นในสถานที่ที่ปลอดภัย
การสร้างรหัส คีย์ API
เพื่อให้บอทของบุคคลที่สามของคุณสามารถเข้าถึงข้อมูลของคุณเพื่อเก็บข้อมูล ข้อมูลที่ใช้ระบุตัวบุคคลได้ (PII)ของผู้ใช้ได้, สร้างกุญแจ Open Cloud API ที่สามารถ
รับรหัสของประสบการณ์และสถานที่
สำหรับบอทที่จะค้นหาข้อมูล PII ที่ต้องการโดยผู้ใช้สำหรับการลบรับรหัสตัวตนของทุกประสบการณ์ที่คุณตั้งใจจะใช้บอทสำหรับ:
- รหัสจักรวาล ซึ่งเป็นรหัสอธิบายอย่างเฉพาะของประสบการณ์ของคุณ
- ตัวระบุสถานที่เริ่มต้น ซึ่งเป็นรหัสไม่ซ้ำกันของสถานที่เริ่มต้นของประสบการณ์
เพื่อรับรหัสเหล่านี้ให้เปิดหน้า สร้าง ที่ ครีเอเตอร์ดาชาร์ดเดสก์ แล้วเลือกประสบการณ์และคัดลอก รหัสจักรวาล และ 2>สถานที่เริ่มต้น2>
การเพิ่มสคริปต์
หลังจากที่คุณเสร็จสิ้นการติดตั้ง webhook, bot, และ API Key สำหรับคลังข้อมูลข้อมูล, เพิ่มพวกเขาในสคริปที่เรียกใช้โลจิกส์อัตโนมัติของบอท ตัวอย่างต่อไปใช้ Python 3:
ติดตั้งห้องสมุด Python โดยใช้คำสั่งต่อไปนี้:
ติดตั้งห้องสมุดpip3 install discordpip3 install guilded.py==1.8.0pip3 install requestspip3 install urllib3==1.26.6คัดลอกและบันทึกสคริปต์ต่อไปนี้ที่เกี่ยวข้องกับแต่ละส่วนของโบร็ตโลจิกในไดเรกทอรีเดียวกัน:
bot_config.pyDISCORD_BOT_TOKEN = ""GUILDED_BOT_TOKEN = ""OPEN_CLOUD_API_KEY = ""ROBLOX_WEBHOOK_SECRET = ""# พจนานุกรมของ Start ที่# (รหัสจักรวาล, รายการ (ชื่อเก็บข้อมูล, ขอบเขต, คีย์)) สำหรับ# ห้องเก็บข้อมูลมาตรฐาน# ข้อมูลผู้ใช้ที่เก็บไว้ภายใต้รายการเหล่านี้จะถูกลบออกSTANDARD_DATA_STORE_ENTRIES = {# รหัสสถานที่เริ่มต้น111111111: (# รหัสจักรวาล222222222,[("StandardDataStore1", "Scope1", "Key1_{user_id}"),("StandardDataStore1", "Scope1", "Key2_{user_id}"),("StandardDataStore2", "Scope1", "Key3_{user_id}")]),33333333: (444444444,[("StandardDataStore3", "Scope1", "Key1_{user_id}")])}# พจนานุกรมของ Start ที่# (รหัสจักรวาล, รายการ (ชื่อเก็บข้อมูล, ขอบเขต, คีย์)) สำหรับ# ร้านค้าข้อมูล# ข้อมูลผู้ใช้ที่เก็บไว้ภายใต้รายการเหล่านี้จะถูกลบออกORDERED_DATA_STORE_ENTRIES = {111111111: (222222222,[("OrderedDataStore1", "Scope2", "Key4_{user_id}")])}data_stores_apiimport 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, failuresข้อความ_ผู้ประมวลผล.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# ป้องกันการโจมตีที่เล่นซ้ำภายในหน้าต่าง 300 วินาทีrequest_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# รับรองลายเซ็น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# ตราที่ถูกต้องreturn 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):# รับข้อความสำหรับ ID ผู้ใช้และ ID เกม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_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):# รับและตรวจสอบข้อความuser_id, start_place_ids = message_parser.parse_message(message)if not user_id or not start_place_ids:return# ลบข้อมูลผู้ใช้จากระเบียนผู้ใช้[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)}")# ลบข้อมูลที่เก็บไว้ของผู้ใช้[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()ในไฟล์ bot_config.py สำหรับการกำหนดค่าหลักของบอท:
- ตั้ง DISCORD_BOT_TOKEN หรือ GUILDED_BOT_TOKEN ให้เป็นโทเค็นที่สร้างโดยบอตของคุณ
- ตั้ง OPEN_CLOUD_API_KEY ให้เป็นรหัส API ที่คุณสร้างขึ้น
- ตั้ง ROBLOX_WEBHOOK_SECRET แดชบอร์ดครีเอเตอร์บนหน้าผู้ใช้
- ใน STANDARD_DATA_STORE_ENTRIES และ ORDERED_DATA_STORE_ENTRIES พจนานุกรมสำหรับการค้นหาคลังข้อมูลของแต่ละบันทึกเพื่อลบ:
- เพิ่มรหัส Start Place ที่คุณเคยคัดลอกเป็นสี่สัญลักษณ์
- เพิ่มรหัสจักรวาลเป็นองค์ประกอบแรกของค่าตัวต้นแบบ
- แทนส่วนที่สองของตารางด้วยชื่อ ขอบเขต ชื่อกุญแจเข้าถึง และรหัสผู้ใช้ที่เกี่ยวข้องของร้านค้าข้อมูลของคุณ หากคุณใช้รูปแบบข้อมูลที่แตกต่างกันโปรดปรับแต่งตามลำดับตามลำดับตามลำดับตามลำดับตามลำ
ประเภทคำสั่งต่อไปนี้เพื่อดำเนินการบอท:
ดำเนินการบอทกิลด์python3 guilded_bot.pyบอทจะเริ่มต้นที่จะฟังและยืนยัน Roblox webhook สำหรับสิทธิ์ในการลบขอและโทรที่ Open Cloud ร้านค้า
การทดสอบ
คุณสามารถสร้างและดำเนินการข้อความทดสอบเพื่อยืนยันว่าโปรแกรมของคุณสามารถจัดการกับคำขอลบที่เหมาะสมและลบข้อมูล PII ได้:
ส่งคำขอ HTTP POST ไปยังเซิร์ฟเวอร์ของคุณ Guilded หรือ Discord webhook ร่างกาย:
คำขอตัวอย่าง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}"}}]}'หากคุณมีคําสั่งเว็บขูกขั้นสูง:
- สร้าง Roblox-Signature โดยการใช้การเข้ารหัส HMAC-SHA256 คีย์
- ตั้งเวลาปัจจุบันโดยใช้เวลายืนยัน UTC ในวินาทีเป็น Timestamp
วาง คำอธิบาย ในรูปแบบต่อไปนี้:
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}`.เช่น:
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
โปรแกรมของคุณควรสามารถระบุได้ว่าข้อความของคุณมาจากที่ที่ Roblox ทางการแล้วเนื่องจากคุณเข้ารหัสข้อความด้วยความลับของคุณ จึงควรลบข้อมูล PII ที่เกี่ยวข้องกับคำขอของคุณ
ตัวอย่างบอดี้
{
"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/dash/ assets/webhook/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}