// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package getproviders

import (
	"bytes"
	"testing"

	"github.com/ProtonMail/go-crypto/openpgp"
	"github.com/ProtonMail/go-crypto/openpgp/armor"
)

// This file contains only some helper functions for the tests in package_authentication_test.go.
// There are not actually any tests in here.
//
// We use these helpers sparingly to minimize the number of opaque-to-humans artifacts
// we need to include as hard-coded constants, instead deriving the opaque artifacts from
// more human-accessible artifacts where possible. However, we must be careful to make sure
// that our use of these helpers does not cause a test to effectively "cheat" by creating
// a situation that could not possibly occur in realistic use.

// pgpTestEntity returns a freshly-generated [openpgp.Entity] with the given name and
// a hard-coded comment and fake email address. The private key is generated randomly
// on request.
//
// We generate keys on the fly, rather than hard-coding them, to avoid dealiing with the
// noise generated by zealous security scanners that get (justifyably) nervous when
// they find a private key included directly in the source code of a codebase. However,
// this just-in-time generation does unfortunately come at a small performance cost,
// so tests should avoid calling this from inside a loop.
func pgpTestEntity(t *testing.T, name string) *openpgp.Entity {
	t.Helper()

	entity, err := openpgp.NewEntity(name, "throwaway key used only for testing", "testing@invalid", nil)
	if err != nil {
		t.Fatalf("failed to generate a PGP key for testing: %s", err)
	}
	return entity
}

// pgpPublicKeyForTestEntity returns an "armored" representation of the public key
// of the given entity, as we'd expect to obtain from an OpenTofu provider
// registry when performing GPG verification of a provider release, and
// a hex representation of the key's ID that we'd use to report the use of
// the key in a successful authentication result.
func pgpPublicKeyForTestEntity(t *testing.T, entity *openpgp.Entity) ([]byte, string) {
	// The "armored" representation, described in RFC 4880 chapter 6,
	// is a PEM-like ASCII-only representation of key data. Therefore
	// we have two layers to deal with here: the armor encoding, and
	// the inner raw representation of the public key.

	var buf bytes.Buffer
	w, err := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", nil)
	if err != nil {
		t.Fatalf("failed to begin ASCII-armored public key block: %s", err)
	}
	err = entity.Serialize(w)
	if err != nil {
		t.Fatalf("failed to serialize the public key part of the PGP entity: %s", err)
	}
	err = w.Close()
	if err != nil {
		t.Fatalf("failed to add ASCII-armor footer: %s", err)
	}
	return buf.Bytes(), entity.PrimaryKey.KeyIdString()
}

// pgpSignForTesting generates a signature for the given message using the private
// key from the given signer, in the raw binary format we'd normally expect to
// receive from an artifact linked in an OpenTofu provider registry.
func pgpSignForTesting(t *testing.T, message []byte, signer *openpgp.Entity) []byte {
	t.Helper()

	var buf bytes.Buffer
	err := openpgp.DetachSign(&buf, signer, bytes.NewReader(message), nil)
	if err != nil {
		t.Fatalf("failed to PGP sign message for testing: %s", err)
	}
	return buf.Bytes()
}
