Các quy định chung về bảo vệ dữ liệu (GDPR) là một quy định chung về bảo vệ dữ liệu và riêng tư của châu Âu. Nó cho phép người ta quyền yêu cầu việc xóa dữ liệu cá nhân của họ, xác định là <
Thay vì xử lý yêu cầu thủ công nhân, bạn có thể tạo một webhook và sử dụng một bot trong một ứng dụng truyền tin thứ ba để tự động hóa quá trình này. Khi lưu trữ dữ liệu là cách phổ biến nhấ
Hồ sơ
Sau khi hoàn thành hướng dẫn này, bạn nên có thể tạo một chương trình tùy chỉnh chạy ở địa phương để tự động hóa quy trình xử lý các yêu cầu quyền truy cập được xóa ngay từ người dùng. Workflow cho quá trình này như sau:
- Roblox Support nhận được quyền yêu cầu xóa bỏ từ một người dùng.
- Roblox webhook được kích hoạt, bao gồm User ID và một danh sách Start Place ID cho các trải nghiệm mà họ đã tham gia trong payload.
- Bot của bạn lắng nghe các thông báo webhook này, xác minh sự xác thực của chúng và sử dụng Open Cloud API for data stores để xóa dữ liệu lưu trữ trong các kho dữ liệu.
- Bot trả lời tin nhắn webhook trong Discord hoặc Guilded với trạng thái xóa.
Tùy chỉnh một Webhook với tích hợp của bên thứ ba
Trước khi tạo một bot, cài đặt một máy chủ với sự tích hợp webhook trên ứng dụng nhắn tin thứ ba. Sau đó, sử dụng máy chủ để cấu hình một webhook trên Creator Dashboard.
Tạo một máy chủ
Các bước tiếp theo cho thấy cách cài đặt máy chủ bằng Guilded hoặc Discord.
- Tạo một máy chủ mới. Nếu bạn không quen với quá trình này, xem Hỗ trợ Guilded.
- Trong cài đặt riêng tư , thiết lập máy chủ là riêng tư. Máy chủ tự động tạo một kênh riêng tư mặc định của bạn như kênh mặc định của bạn.
- Tạo một kết nối webhook với máy chủ mới và đặt tên cho nó mà bạn có thể dễ dàng hiểu, chẳng hạn như GDPR Hook. Nếu bạn không quen với quá trình này, hãy xem Hỗ trợ bang hội.
- Bản sao URL webhook và lưu nó ở một địa điểman toàn. Chỉ cho phép các thành viên trong nhóm được ủy quyền truy cập nó, vì việc rò rỉ URL có thể cho phép các kẻ tấn công xấu để gửi các thông điệp giả mạo và có thể xóa dữ liệu người dùng của bạn.
Tùy chỉnh một Webhook trên Roblox
Sau khi nhận được URL của máy chủ thứ ba, hãy sử dụng nó để tùy chỉnh một webhook trên Creator Dashboard. chắc chắn bạn thực hiện các cài đặt sau:
- Thêm URL của máy chủ Guilded hoặc Discord như là URL của Webhook .
- Bao gồm một Secret tùy chỉnh. Mặc dù một secret là tùy chọn cho hoàn thành cấu hình, bạn nên bao gồm một để ngăn chặn các kẻ xấu làm giả Roblox và xóa dữ liệu của bạn. Đối với thông tin về sử dụng của một secret, hãy xem Xác minh bảo mật Webhook.
- Chọn Yêu cầu xóa bỏ phải dưới Mục trí .
Bạn có thể kiểm tra webhook bằng nút Test Request để xem có phải nhận được thông báo trong kênh # general của Roblox. Nếu bạn không nhận được thông báo, hãy thử lại hoặc kiểm tra cài đặt máy chủ của bạn để xác minh lỗi.
Tùy chỉnh một Bot
Sau khi bạn thêm webhook, hãy sử dụng nó để cấu hình bot bằng các bước sau đây:
Mở danh sách Tất cả các máy chủ bằng cách nhấp vào biểu tượng của nó hoặc sử dụng cách thẳng:
- CtrlS trên Windows.
- ⌘S trên Mac.
Chọn máy chủ của bạn để nhận các thông báo quyền truy cập để xóa.
Mở danh sách dưới Trang chủ máy chủ và chọn Quản lý Bots .
Máy chủ tự động tạo một kênh # general riêng của bạn như kênh mặc định của bạn.
Nhấp vào nút Tạo một bot và thêm tên bot. Guilded chuyển bạn đến trang cài đặt bot.
Chọn API section on the bot configuration page.
Trong phần Token, nhấp vào nút Tạo Token.
Lưu và lưu trữ token đã tạo ở một địa điểman toàn.
Tạo một Chìa khóa API Mở đám mây
Để cho phép bot của bên thứ ba của bạn truy cập vào các kho dữ liệu của bạn để lưu trữ dữ liệu TTCNcủa người dùng, tạo một chìa khóa Open Cloud API có thể truy cập vào trải nghiệm củ
Nhận Xác Thực Hóa Để Nhận Danh Nghĩa Của Trải Nghiệm và Địa Điểm
Để bot tìm kiếm dữ liệu PII yêu cầu của người dùng để xóa, hãy nhận xác định của tất cả các trải nghiệm mà bạn định sử dụng bot cho:
- ID Thế giới, một mã độc nhất của trải nghiệm của bạn.
- The Start Place ID , the unique identifier of the start place of an kinh nghiệm.
Để có được các xác tín này, hãy mở trang Tạo bản sao trên Bảng điều khiển của người sáng tạo. Sau đó, chọn một trải nghiệm và sao chép ID Universe và 2>Start Place ID2>.
Thêm Scripts
Sau khi bạn kết thúc cài đặt webhook, bot và API key cho các kho dữ liệu, thêm chúng vào các script thực hiện công việc tự động hóa của bot. Các ví dụ sau đây sử dụng Python 3:
Cài đặt thư viện Python bằng các lệnh sau đây:
Cài đặt thư việnpip3 install discordpip3 install guilded.py==1.8.0pip3 install requestspip3 install urllib3==1.26.6Sao chép và lưu các script sau đây tương ứng với các bộ phận khác nhau của bot logic trong cùng một thư mục:
bot_config.pyDISCORD_BOT_TOKEN = ""GUILDED_BOT_TOKEN = ""OPEN_CLOUD_API_KEY = ""ROBLOX_WEBHOOK_SECRET = ""# Dictionary of the Start place ID đến# (ID vũ trụ, danh sách (các cửa hàng dữ liệu, phạm vi và chìa khóa)) cho# Các cửa hàng dữ liệu tiêu chuẩn# Dữ liệu người dùng được lưu dưới các mục này sẽ bị xóaSTANDARD_DATA_STORE_ENTRIES = {# ID địa điểm khởi đầu111111111: (# ID Universe222222222,[("StandardDataStore1", "Scope1", "Key1_{user_id}"),("StandardDataStore1", "Scope1", "Key2_{user_id}"),("StandardDataStore2", "Scope1", "Key3_{user_id}")]),33333333: (444444444,[("StandardDataStore3", "Scope1", "Key1_{user_id}")])}# Dictionary of the Start place ID đến# (ID vũ trụ, danh sách (các cửa hàng dữ liệu, phạm vi và chìa khóa)) cho# Các Cửa Hàng Dữ Liệu Đã Đặt Hàng# Dữ liệu người dùng được lưu dưới các mục này sẽ bị xóaORDERED_DATA_STORE_ENTRIES = {111111111: (222222222,[("OrderedDataStore1", "Scope2", "Key4_{user_id}")])}api_lưu_trữ_dữ_liệu.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, 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# Ngăn chặn cuộc tấn công lặp lại trong cửa sổ 300 giâyrequest_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# Xác thực hồ sơ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# Chữ ký hợp lệ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):# Nhận tin nhắn đã được mã hóa cho ID người chơi và ID trò chơiif 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):# Tách và xác minh thông tin nhắnuser_id, start_place_ids = message_parser.parse_message(message)if not user_id or not start_place_ids:return# Xóa dữ liệu người dùng của các cửa hàng dữ liệu tiêu chuẩn[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)}")# Xóa các cử chỉ dữ liệu đã được lưu[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()Trên các tập tin bot_config.py để cấu hình chính của bot:
- Đặt DISCORD_BOT_TOKEN hoặc GUILDED_BOT_TOKEN vào token được tạo bởi bot của bạn.
- Đặt OPEN_CLOUD_API_KEY làm chìa khóa API bạn đã tạo.
- Đặt ROBLOX_WEBHOOK_SECRET như một bí mật bạn đã đặt khi cấu hình webhook trên Creator Dashboard.
- Trong STANDARD_DATA_STORE_ENTRIES và ORDERED_DATA_STORE_ENTRIES bản từ điển để tìm dữ liệu lưu trữ của mỗi ghi lại để xóa:
- Thêm Start Place ID của bạn vào các dấu hiệu.
- Thêm ID Universe như một yếu tố đầu tiên của giá trị tuần tục.
- Thay thế thứ hai của tuỳ chỉnh với tên, phạm vi, tên chìa khóa nhập và ID người dùng liên quan. Nếu bạn sử dụng một cấu hình dữ liệu khác, chỉnh sửa để phù hợp với dữ liệu của riêng bạn sau đó.
Thực hiện lệnh sau đây để thiết lập và thi hành bot:
Chạy Bot Đã Guildpython3 guilded_bot.pyBot sau đó bắt đầu lắng nghe và xác minh các webhook Roblox để có quyền truy cập vào các yêu cầu xóa và gọi điểm dịch vụ Open Cloud để xóa kho dữ cửa hàngtương ứng.
Làm thử
Bạn có thể tạo và chạy một thông điệp thử nghiệm để xác nhận rằng chương trình tùy chỉnh của bạn có thể xử lý đúng các yêu cầu để xóa dữ liệu PII:
Gửi một yêu cầu HTTP POST đến máy chủ webhook của bạn với thân bằng yêu cầu như sau:
Yêu cầu ví dụ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}"}}]}'Nếu bạn có một cú đột kẻ thù:
- Tạo một Roblox-Signature bằng cách áp dụng mã mã hóa HMAC-SHA256 vào chìa khóa webhook của bạn.
- Set the current time using UTC timestamp in seconds as Timestamp .
Đặt các description lại với nhau theo định dạng sau:
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}`.Ví dụ:
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
Chương trình của bạn nên có thể xác định rằng tin nhắn của bạn đến từ nguồn Roblox chính thức vì bạn đã mã hóa tin nhắn với bí mật của bạn. Sau đó, nó nên xóa dữ liệu PII liên quan với yêu cầu của bạn.
Thân hình ví dụ
{
"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/ assets/ webhook/roblox_logo_metal.png",
"text": "Roblox-Signature: UIe6GJ78MHCmU/zUKBYP3LV0lAqwWRFR6UEfPt1xBFw=, Timestamp: 1683927229"
}
}
]
}