Ctrl K
ComunidadGuías…

test/integration/oauth_grant_reach_test.rb

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
require "test_helper"

# An OAuth grant acts for an app on the user's data. It may not manage the
# user's credentials or consent to apps: anything it minted there would outlive
# disconnecting the app, and anything it removed would be someone else's.
class OauthGrantReachTest < ActionDispatch::IntegrationTest
  setup do
    @grant = identities(:david).access_tokens.create!(oauth_client: oauth_clients(:mcp_client), permission: :write)
    @bearer = { "HTTP_AUTHORIZATION" => "Bearer #{@grant.raw_token}" }
  end

  test "an OAuth grant can't consent to an app" do
    untenanted do
      post oauth_authorization_path, params: { client_id: oauth_clients(:trusted_client).client_id, redirect_uri: oauth_clients(:trusted_client).redirect_uris.first,
        response_type: "code", code_challenge: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM", code_challenge_method: "S256", scope: "read write", state: "s" },
        env: @bearer, as: :json
    end

    assert_response :forbidden
  end

  test "an OAuth grant can't disconnect an app" do
    other = identities(:david).access_tokens.create!(oauth_client: oauth_clients(:trusted_client))

    delete my_connected_app_path(oauth_clients(:trusted_client)), env: @bearer, as: :json

    assert_response :forbidden
    assert Identity::AccessToken.exists?(other.id)
  end

  test "an OAuth grant can't register a passkey" do
    post my_passkeys_path, params: { passkey: { client_data_json: "{}" } }, env: @bearer, as: :json
    assert_response :forbidden
  end

  test "an OAuth grant can't mint a transfer link" do
    post transfer_token_path, env: @bearer, as: :json

    assert_response :forbidden
  end

  test "an OAuth grant can't change the user's email address" do
    assert_no_emails do
      post user_email_addresses_path(users(:david)), params: { email_address: "app-controlled@example.com" }, env: @bearer, as: :json
    end

    assert_response :forbidden
  end

  test "an OAuth grant can't read or reset the account's join code" do
    code = accounts("37s").join_code.code

    get account_join_code_path, env: @bearer, as: :json
    assert_response :forbidden

    delete account_join_code_path, env: admin_grant, as: :json
    assert_response :forbidden
    assert_equal code, accounts("37s").join_code.reload.code
  end

  test "an OAuth grant can't export the account, which carries its join code and webhook credentials" do
    assert_no_difference -> { Account::Export.count } do
      post account_exports_path, env: admin_grant, as: :json
    end
    assert_response :forbidden

    export = Account::Export.create!(account: accounts("37s"), user: users(:kevin))
    get account_export_path(export), env: admin_grant, as: :json
    assert_response :forbidden
  end

  test "an OAuth grant reads webhooks without their credentials" do
    webhook = webhooks(:active)

    get board_webhooks_path(webhook.board), env: admin_grant, as: :json
    assert_response :success
    assert_equal webhook.id, @response.parsed_body.first["id"]
    assert_webhook_credentials_withheld @response.parsed_body.first

    get board_webhook_path(webhook.board, webhook), env: admin_grant, as: :json
    assert_response :success
    assert_webhook_credentials_withheld @response.parsed_body

    put board_webhook_path(webhook.board, webhook), params: { webhook: { name: "Renamed" } }, env: admin_grant, as: :json
    assert_response :success
    assert_equal "Renamed", @response.parsed_body["name"]
    assert_webhook_credentials_withheld @response.parsed_body

    post board_webhook_activation_path(webhook.board, webhook), env: admin_grant, as: :json
    assert_response :created
    assert_webhook_credentials_withheld @response.parsed_body
  end

  test "an OAuth grant gets a webhook's credentials once, when it creates it" do
    post board_webhooks_path(boards(:writebook)), params: { webhook: { name: "App", url: "https://app.example.com/hooks" } }, env: admin_grant, as: :json

    assert_response :created
    webhook = Webhook.find(@response.parsed_body["id"])
    assert_equal webhook.signing_secret, @response.parsed_body["signing_secret"]
    assert_equal "https://app.example.com/hooks", @response.parsed_body["payload_url"]

    get board_webhook_path(webhook.board, webhook), env: admin_grant, as: :json
    assert_webhook_credentials_withheld @response.parsed_body
  end

  test "a personal access token still reads the join code and webhook credentials" do
    webhook = webhooks(:active)
    pat = { "HTTP_AUTHORIZATION" => "Bearer #{identities(:kevin).access_tokens.create!(permission: :read).raw_token}" }

    get account_join_code_path, env: pat, as: :json
    assert_response :success
    assert_equal accounts("37s").join_code.code, @response.parsed_body["code"]

    get board_webhook_path(webhook.board, webhook), env: pat, as: :json
    assert_response :success
    assert_equal webhook.signing_secret, @response.parsed_body["signing_secret"]
    assert_equal webhook.url, @response.parsed_body["payload_url"]
  end

  test "a personal access token still manages personal access tokens" do
    pat = { "HTTP_AUTHORIZATION" => "Bearer #{identity_access_tokens(:davids_api_token).token}" }

    get my_access_tokens_path, env: pat, as: :json

    assert_response :success
  end

  private
    def admin_grant
      token = identities(:kevin).access_tokens.create!(oauth_client: oauth_clients(:mcp_client), permission: :write).raw_token
      { "HTTP_AUTHORIZATION" => "Bearer #{token}" }
    end

    def assert_webhook_credentials_withheld(json)
      assert_not json.key?("signing_secret"), "expected no signing_secret in #{json.keys}"
      assert_not json.key?("payload_url"), "expected no payload_url in #{json.keys}"
    end
end