mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-11 08:06:01 -05:00
Refactor tests to not include private keys in database records for remote keypairs (#39682)
This commit is contained in:
@@ -31,8 +31,6 @@ class Keypair < ApplicationRecord
|
||||
ed25519: 1,
|
||||
}, validate: true
|
||||
|
||||
attr_accessor :require_private_key
|
||||
|
||||
validates :uri, presence: true, uniqueness: true, if: -> { account.remote? }
|
||||
validates :uri, absence: true, if: -> { account.local? }
|
||||
|
||||
@@ -41,9 +39,7 @@ class Keypair < ApplicationRecord
|
||||
|
||||
validates :public_key, presence: true
|
||||
validates :private_key, presence: true, if: -> { account.local? }
|
||||
|
||||
# NOTE: this should be true in production, but tests heavily rely on remote accounts having a keypair
|
||||
validates :private_key, absence: true, if: -> { account.remote? && !require_private_key }
|
||||
validates :private_key, absence: true, if: -> { account.remote? }
|
||||
|
||||
scope :unexpired, -> { where(expires_at: nil).or(where.not(expires_at: ..Time.now.utc)) }
|
||||
scope :usable, -> { unexpired.where(revoked: false) }
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
keypair = OpenSSL::PKey::RSA.new(2048)
|
||||
public_key = keypair.public_key.to_pem
|
||||
private_key = keypair.to_pem
|
||||
|
||||
Fabricator(:account) do
|
||||
transient :suspended, :silenced
|
||||
username { sequence(:username) { |i| "#{Faker::Internet.user_name(separators: %w(_))}#{i}" } }
|
||||
last_webfingered_at { Time.now.utc }
|
||||
public_key { public_key }
|
||||
private_key { private_key }
|
||||
public_key { SigningKeysHelpers::PUBLIC_RSA_TEST_KEY }
|
||||
private_key { |attrs| attrs[:domain].present? ? nil : SigningKeysHelpers::PRIVATE_RSA_TEST_KEY }
|
||||
suspended_at { |attrs| attrs[:suspended] ? Time.now.utc : nil }
|
||||
silenced_at { |attrs| attrs[:silenced] ? Time.now.utc : nil }
|
||||
user { |attrs| attrs[:domain].nil? ? Fabricate.build(:user, account: nil) : nil }
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
keypair = OpenSSL::PKey::RSA.new(2048)
|
||||
public_key = keypair.public_key.to_pem
|
||||
private_key = keypair.to_pem
|
||||
|
||||
Fabricator(:keypair) do
|
||||
account
|
||||
type :rsa
|
||||
public_key public_key
|
||||
public_key SigningKeysHelpers::PUBLIC_RSA_TEST_KEY
|
||||
expires_at nil
|
||||
revoked false
|
||||
|
||||
after_build do |keypair|
|
||||
if keypair.account.local?
|
||||
keypair.private_key ||= private_key
|
||||
keypair.private_key ||= SigningKeysHelpers::PRIVATE_RSA_TEST_KEY
|
||||
keypair.local_fragment ||= "##{Random.hex}"
|
||||
else
|
||||
keypair.uri ||= ActivityPub::TagManager.instance.key_uri_for(keypair.account)
|
||||
|
||||
@@ -146,6 +146,8 @@ RSpec.describe ActivityPub::LinkedDataSignature do
|
||||
describe '#sign!' do
|
||||
subject { described_class.new(raw_json).sign!(sender) }
|
||||
|
||||
let(:sender) { Fabricate(:account) }
|
||||
|
||||
it 'returns a hash with a signature, the expected context, and the signature can be verified', :aggregate_failures do
|
||||
expect(subject).to be_a Hash
|
||||
expect(subject['signature']).to be_a Hash
|
||||
@@ -159,6 +161,6 @@ RSpec.describe ActivityPub::LinkedDataSignature do
|
||||
options_hash = Digest::SHA256.hexdigest(canonicalize(options.merge('@context' => ActivityPub::LinkedDataSignature::CONTEXT)))
|
||||
document_hash = Digest::SHA256.hexdigest(canonicalize(document))
|
||||
to_be_verified = options_hash + document_hash
|
||||
Base64.strict_encode64(from_actor.keypair.keypair.sign(OpenSSL::Digest.new('SHA256'), to_be_verified))
|
||||
Base64.strict_encode64(private_key_from_keypair(from_actor.keypair).sign(OpenSSL::Digest.new('SHA256'), to_be_verified))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -88,6 +88,7 @@ RSpec.configure do |config|
|
||||
config.include Redisable
|
||||
config.include DomainHelpers
|
||||
config.include ThreadingHelpers
|
||||
config.include SigningKeysHelpers
|
||||
config.include SignedRequestHelpers, type: :request
|
||||
config.include CommandLineHelpers, type: :cli
|
||||
config.include SystemHelpers, type: :system
|
||||
|
||||
@@ -12,7 +12,8 @@ module SignedRequestHelpers
|
||||
keypair = sign_with.keypair
|
||||
key_id = keypair.uri
|
||||
signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
|
||||
signature = Base64.strict_encode64(keypair.keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
|
||||
|
||||
signature = Base64.strict_encode64(private_key_from_keypair(keypair).sign(OpenSSL::Digest.new('SHA256'), signed_string))
|
||||
|
||||
headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
|
||||
|
||||
@@ -32,7 +33,7 @@ module SignedRequestHelpers
|
||||
keypair = sign_with.keypair
|
||||
key_id = keypair.uri
|
||||
signed_string = signed_headers.map { |key, value| "#{key.downcase}: #{value}" }.join("\n")
|
||||
signature = Base64.strict_encode64(keypair.keypair.sign(OpenSSL::Digest.new('SHA256'), signed_string))
|
||||
signature = Base64.strict_encode64(private_key_from_keypair(keypair).sign(OpenSSL::Digest.new('SHA256'), signed_string))
|
||||
|
||||
headers['Signature'] = "keyId=\"#{key_id}\",algorithm=\"rsa-sha256\",headers=\"#{signed_headers.keys.join(' ').downcase}\",signature=\"#{signature}\""
|
||||
|
||||
|
||||
57
spec/support/signing_keys_helpers.rb
Normal file
57
spec/support/signing_keys_helpers.rb
Normal file
@@ -0,0 +1,57 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module SigningKeysHelpers
|
||||
PUBLIC_RSA_TEST_KEY = <<~RSA
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuD7++C+IYBzC96Na27S5
|
||||
qqJhE6OSAe3/1r/hhGlvCl5a415Ma+wDDyHp8LcRI9fLcuyo+Hc0DNiBmjlNc9Oa
|
||||
TDlhfx917cYV7bHbw3yT0OcwcavsgnZBd3GRVaMgY0thAuLtw7XgMnRy4i2steUJ
|
||||
+anbsiC7F65gWsgvsD4W8Dk3Bmf5r+oDtgfo19t0NPsNM+pXtL1IKbBwnnyzkcO/
|
||||
f2kbSVvHgX7A9X33jca4Kgn1yyw/y5lYANKwi+Um8eEYXPVqWeYGc0/k8ZvcYS6B
|
||||
w0XWHLG9kjQU/ApoKlaLshmU46sCDKkJKw0p58urOV9vtwaAbx+0NK9GaU7C5QSa
|
||||
vQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
RSA
|
||||
|
||||
PRIVATE_RSA_TEST_KEY = <<~RSA
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAuD7++C+IYBzC96Na27S5qqJhE6OSAe3/1r/hhGlvCl5a415M
|
||||
a+wDDyHp8LcRI9fLcuyo+Hc0DNiBmjlNc9OaTDlhfx917cYV7bHbw3yT0Ocwcavs
|
||||
gnZBd3GRVaMgY0thAuLtw7XgMnRy4i2steUJ+anbsiC7F65gWsgvsD4W8Dk3Bmf5
|
||||
r+oDtgfo19t0NPsNM+pXtL1IKbBwnnyzkcO/f2kbSVvHgX7A9X33jca4Kgn1yyw/
|
||||
y5lYANKwi+Um8eEYXPVqWeYGc0/k8ZvcYS6Bw0XWHLG9kjQU/ApoKlaLshmU46sC
|
||||
DKkJKw0p58urOV9vtwaAbx+0NK9GaU7C5QSavQIDAQABAoIBABxnIbky4qwmYuv4
|
||||
E86g2qpyY9K6OYzwmqsJY4OdGVAY4ZwBcniEpqgTi1PfdNX4s1VhJF9BSRXd3oTe
|
||||
5pC/gx7TDbOiLvTbv4+oBn/pWYQvz6kGXuxxvH/kUwpHnnuQKEFgqFSuWgSNLRSv
|
||||
A9v6lgIV7FdWcmEhMZttFuTtfW3EsTtL6Agjj6pNpREdgDQ4vu8LIMpTW9OOxee7
|
||||
Ui5oNSc+HNxsEo+Tb0pqfTuD6iztRIxLfBRS8M4EK9UTO82H4qYMb9HI6XfBshQ7
|
||||
3hhh9tDvo2QgX4L4FW8z64kmNli4MdhG+HDC2HWqX+f/4GxZUsUPWTkUVCS/nw2O
|
||||
JqYW+cECgYEA3ktP58HFbx3zfK1MdB2GjhyTMQqiP4VH50qj0VWvqEFdcP6nlMj4
|
||||
mhSwIhJJ2rzlclV0e5TAcHrWDx20Bpo72YfFORqMVIwXO5ZV9z3Xc83fu3KjUscv
|
||||
5UAghznN2Qc4CsxEI/I8/LMpLP2aua6RQPfQYk8LcdrafK7WBdkkF80CgYEA1C7J
|
||||
1xeIJHJxiLQ8g4g3BSPOP6MiM2qlQyapegWw7NA+sgG0MtTAddaZFkYrtkGZVvNF
|
||||
lFQQCe9SWzW1pwZxHlmOm95PC9B89E+kzoEEUU/scXtP04krp4eUXbuBfTQ0aLU+
|
||||
QZ3FsUkedLVJ8UH8zanY/VnjhtCgXdsT6Mz+vrECgYEAiBs2xqE3QMzm67y0Jhh5
|
||||
7YODgDCRnTD/EJf76816KxwymV/ivc+7n6PxIDtwavTjy/iUxKIUngooDMNUGgLP
|
||||
iGaAFHGz4ISSKRLoeeSsiaRRS9VqOOHq6oQ0Jnf3GN45qyrcweGtA9Cy8nApD23a
|
||||
VBwnxDm/uSuWQWdPde85ETUCgYEAycEjky6A+YcIhaA72iXviyecuc34e0NwmQVu
|
||||
KOS4crUgqEoOejbqOiIvtopKjiaaE5+GDaBRD+FMQgY0D/mEHgOyImukZet8pSIF
|
||||
54WuAVMp1E4YfV/07ntwjB/65H57RwTviZznmceY+ghXotvH8hcKiPyr6Ej/876Y
|
||||
k8g4gkECgYEAvN2GfwrLOgYaS3M0uldpOCHqod9zFABmzlmGn6+VLVkskFAA/RiC
|
||||
NO+Pm38bh3FbxBhLXM4sTGHn157/WCvaCSUSsjGJCkOemhXOJ+zEvo6yqANrtGMt
|
||||
f5zmr3d79JfG+WJbzZj7eO6LNbf2RHQKtuTLYNl0vmRpIcMaYJ8deNo=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
RSA
|
||||
|
||||
# Keypairs for remote actors typically do not include their private keys,
|
||||
# but we need to sign requests in tests. So use the known test private key
|
||||
# for known test public keys when testing.
|
||||
def private_key_from_keypair(keypair)
|
||||
case keypair.public_key
|
||||
when PUBLIC_RSA_TEST_KEY
|
||||
OpenSSL::PKey.read(PRIVATE_RSA_TEST_KEY)
|
||||
else
|
||||
OpenSSL::PKey.read(keypair.private_key)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user