Tự động hóa yêu cầu xóa

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

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:

  1. Roblox Support nhận được quyền yêu cầu xóa bỏ từ một người dùng.
  2. 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.
  3. 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.
  4. 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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.

Example notification on Guilded

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:

  1. 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.
  2. Chọn máy chủ của bạn để nhận các thông báo quyền truy cập để xóa.

  3. Mở danh sách dưới Trang chủ máy chủ và chọn Quản lý Bots .

  4. 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.

  5. 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.

  6. Chọn API section on the bot configuration page.

  7. Trong phần Token, nhấp vào nút Tạo Token.

  8. 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>.

Copy Universe ID and Copy Start Place ID options from Creator Dashboard

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:

  1. Cài đặt thư viện Python bằng các lệnh sau đây:

    Cài đặt thư viện

    pip3 install discord
    pip3 install guilded.py==1.8.0
    pip3 install requests
    pip3 install urllib3==1.26.6
  2. Sao 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.py

    DISCORD_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óa
    STANDARD_DATA_STORE_ENTRIES = {
    # ID địa điểm khởi đầu
    111111111: (
    # ID Universe
    222222222,
    [
    ("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óa
    ORDERED_DATA_STORE_ENTRIES = {
    111111111: (
    222222222,
    [
    ("OrderedDataStore1", "Scope2", "Key4_{user_id}")
    ]
    )
    }
    api_lưu_trữ_dữ_liệu.py

    import requests
    import bot_config
    from collections import defaultdict
    """
    Calls Data Stores Open Cloud API to delete all entries for a user_id configured in
    STANDARD_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:
    continue
    universe_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 in
    ORDERED_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:
    continue
    universe_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
    消息_ар解码器.py

    import time
    import hmac
    import hashlib
    import re
    import base64
    import bot_config
    """
    Parses received message for Roblox signature and timestamp, the footer is only set if you
    configured webhook secret
    """
    def parse_footer(message):
    if not message.embeds[0].footer or \
    not message.embeds[0].footer.text:
    return "", 0
    footer_match = re.match(
    r"Roblox-Signature: (.*), Timestamp: (.*)",
    message.embeds[0].footer.text
    )
    if not footer_match:
    return "", 0
    else:
    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ây
    request_timestamp_ms = timestamp * 1000
    window_time_ms = 300 * 1000
    oldest_timestamp_allowed = round(time.time() * 1000) - window_time_ms
    if 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 attack
    based on timestamp received, and verifies Roblox signature with configured secret to check for
    validity.
    """
    def parse_message(message):
    # Nhận tin nhắn đã được mã hóa cho ID người chơi và ID trò chơi
    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_ids
    else:
    return "", []
    guilded_bot.py

    import guilded
    import json
    import bot_config
    import data_stores_api
    import message_parser
    def run():
    client = guilded.Client()
    @client.event
    async def on_ready():
    print(f"{client.user} is listening to Right to Erasure messages")
    """
    Handler for webhook messages from Roblox
    """
    @client.event
    async def on_message(message):
    # Tách và xác minh thông tin nhắn
    user_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()
  3. Trên các tập tin bot_config.py để cấu hình chính của bot:

    1. Đặt DISCORD_BOT_TOKEN hoặc GUILDED_BOT_TOKEN vào token được tạo bởi bot của bạn.
    2. Đặt OPEN_CLOUD_API_KEY làm chìa khóa API bạn đã tạo.
    3. Đặt ROBLOX_WEBHOOK_SECRET như một bí mật bạn đã đặt khi cấu hình webhook trên Creator Dashboard.
    4. Trong STANDARD_DATA_STORE_ENTRIESORDERED_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:
      1. Thêm Start Place ID của bạn vào các dấu hiệu.
      2. Thêm ID Universe như một yếu tố đầu tiên của giá trị tuần tục.
      3. 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 đó.
  4. Thực hiện lệnh sau đây để thiết lập và thi hành bot:

    Chạy Bot Đã Guild

    python3 guilded_bot.py
  5. Bot 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:

  1. 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}"
    }
    }]
    }'
  2. Nếu bạn có một cú đột kẻ thù:

    1. 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.
    2. Set the current time using UTC timestamp in seconds as Timestamp .
  3. Đặ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 Field

    1683927229. 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"
}
}
]
}