All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jsuereth.sbtpgp.PgpPlugin.scala Maven / Gradle / Ivy

package bleep.plugin.pgp

import bleep.RelPath
import bleep.nosbt.librarymanagement.ivy.DirectCredentials
import bleep.nosbt.{FileOps, InteractionService}
import ryddig.Logger

import java.io.File

/** SBT Keys for the PGP plugin. */
class PgpPlugin(val logger: Logger, val maybeCredentials: Option[DirectCredentials], val interactionService: InteractionService) {
  val gnuPGHome: File = scala.util.Properties.envOrNone("GNUPGHOME") match {
    case Some(dir) => new File(dir)
    case None      => new File(System.getProperty("user.home")) / ".gnupg"
  }

  def fallbackFiles(fs: File*): File = {
    require(fs.nonEmpty)
    val (h, t) = (fs.head, fs.tail)
    if (t.isEmpty) h
    else if (h.exists) h
    else fallbackFiles(t: _*)
  }

  /* "The location of the key ring, passed to gpg command as --no-default-keyring --keyring . */
  lazy val pgpKeyRing: Option[File] = None

  /* "The location of the secret key ring. Only needed if using Bouncy Castle. */
  lazy val pgpSecretRing: File =
    fallbackFiles(
      gnuPGHome / "secring.gpg",
      new File(System.getProperty("user.home")) / ".sbt" / "gpg" / "secring.asc"
    )

  /* "The location of the secret key ring. Only needed if using Bouncy Castle. */
  lazy val pgpPublicRing: File =
    fallbackFiles(
      gnuPGHome / "pubring.gpg",
      new File(System.getProperty("user.home")) / ".sbt" / "gpg" / "pubring.asc"
    )

  /* "The passphrase associated with the secret used to sign artifacts. */
  lazy val pgpPassphrase: Option[Array[Char]] = None

  /* "Context used for auto-completing PGP commands. */
  lazy val pgpStaticContext: cli.PgpStaticContext =
    SbtPgpStaticContext(pgpPublicRing, pgpSecretRing)

  /* "The path of the GPG command to run */
  lazy val gpgCommand: String =
    if (isWindows) "gpg.exe" else "gpg"

  /* "If this is set to true, the GPG command line will be used. */
  lazy val useGpg: Boolean =
    sys.props.get("SBT_PGP_USE_GPG") match {
      case Some(_) => java.lang.Boolean.getBoolean("SBT_PGP_USE_GPG")
      case None    => true
    }

  /* "If this is set to true, the GPG command line will expect a GPG agent for the password. */
  lazy val useGpgAgent: Boolean = true

  /* "If this is set to true, the GPG command line will expect pinentry will be used with gpg-agent. */
  lazy val useGpgPinentry: Boolean = false

  /* The helper class to run gpg commands. */
  def pgpSigner(): PgpSigner =
    if (useGpg)
      if (useGpgPinentry)
        new CommandLineGpgPinentrySigner(gpgCommand, useGpgAgent, pgpKeyRing, pgpSigningKey(), pgpSelectPassphrase())
      else
        new CommandLineGpgSigner(gpgCommand, useGpgAgent, pgpKeyRing, pgpSigningKey(), pgpSelectPassphrase())
    else new BouncyCastlePgpSigner(pgpCmdContext(), pgpSigningKey())

  /* The passphrase associated with the secret used to sign artifacts. */
  def pgpSelectPassphrase(): Option[Array[Char]] =
    pgpPassphrase
      .orElse(maybeCredentials.map(_.passwd.toCharArray))
      .orElse(scala.util.Properties.envOrNone("PGP_PASSPHRASE").map(_.toCharArray))

  /* The key used to sign artifacts in this project, passed to gpg command as --default-key . */
  def pgpSigningKey(): Option[String] =
    maybeCredentials.map(_.userName)

  /* Context used to run PGP commands. */
  def pgpCmdContext(): cli.PgpCommandContext =
    SbtPgpCommandContext(
      pgpStaticContext,
      interactionService,
      pgpSelectPassphrase(),
      logger
    )

  /* Packages all artifacts for publishing and maps the Artifact definition to the generated file. */
  def signedArtifacts(files: Map[RelPath, Array[Byte]]): Map[RelPath, Array[Byte]] = {
    val signer = pgpSigner()
    files.flatMap { case in @ (relPath, content) =>
      val signedArtifact = relPath.withLast(_ + gpgExtension)
      val signedContent = signer.sign(content, logger)
      Map(in, (signedArtifact, signedContent))
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy