<commit_before>package libkb

import (
	"fmt"
	"io"
	"os/exec"
	"sync"

	"golang.org/x/crypto/openpgp"
)

type GpgCLI struct {
	path    string
	options []string

	// Configuration --- cache the results
	configured     bool
	configExplicit bool
	configError    error

	mutex *sync.Mutex

	logUI LogUI
}

type GpgCLIArg struct {
	LogUI LogUI // If nil, use the global
}

func NewGpgCLI(arg GpgCLIArg) *GpgCLI {
	logUI := arg.LogUI
	if logUI == nil {
		logUI = G.Log
	}
	return &GpgCLI{
		configured: false,
		mutex:      new(sync.Mutex),
		logUI:      logUI,
	}
}

func (g *GpgCLI) Configure() (configExplicit bool, err error) {

	g.mutex.Lock()
	defer g.mutex.Unlock()

	if g.configured {
		configExplicit = g.configExplicit
		err = g.configError
		return
	}

	prog := G.Env.GetGpg()
	opts := G.Env.GetGpgOptions()

	// If we asked for any explicit GPG options
	configExplicit = (len(prog) > 0 || opts != nil)
	if len(prog) > 0 {
		err = canExec(prog)
	} else {
		prog, err = exec.LookPath("gpg2")
		if err != nil {
			prog, err = exec.LookPath("gpg")
		}
	}

	g.logUI.Debug("| configured GPG w/ path: %s", prog)

	g.path = prog
	g.options = opts
	g.configured = true
	g.configExplicit = configExplicit
	g.configError = err

	return
}

// CanExec returns true if a gpg executable exists.
func (g *GpgCLI) CanExec() (bool, error) {
	if _, err := g.Configure(); err != nil {
		if oerr, ok := err.(*exec.Error); ok {
			if oerr.Err == exec.ErrNotFound {
				return false, nil
			}
		}
		return false, err
	}
	return true, nil
}

// Path returns the path of the gpg executable.  Configure must be
// called before using this.
func (g *GpgCLI) Path() string {
	if !g.configured {
		panic("GpgCLI not configured")
	}
	return g.path
}

type RunGpgArg struct {
	Arguments []string
	Stdin     bool
	Stderr    io.WriteCloser
	Stdout    io.WriteCloser
}

type RunGpgRes struct {
	Stdin io.WriteCloser
	Err   error
	Wait  func() error
}

func (g *GpgCLI) ImportKey(secret bool, fp PGPFingerprint) (ret *PGPKeyBundle, err error) {
	var cmd string
	var which string
	if secret {
		which = "secret"
		cmd = "--export-secret-key"
	} else {
		which = "public"
		cmd = "--export"
	}

	arg := RunGpg2Arg{
		Arguments: []string{cmd, fp.String()},
		Stdout:    true,
	}

	res := g.Run2(arg)
	if res.Err != nil {
		return nil, res.Err
	}

	el, err := openpgp.ReadKeyRing(res.Stdout)
	if err != nil {
		return nil, err
	}
	if err = res.Wait(); err != nil {
		return nil, err
	}
	if len(el) == 0 {
		return nil, NoKeyError{fmt.Sprintf("No %s key for %s found", which, fp.ToKeyID())}
	}
	if len(el) > 1 {
		return nil, TooManyKeysError{len(el), fp}
	}

	return NewPGPKeyBundle(el[0]), nil<commit_msg>Load armored keys from gpg<commit_after>package libkb

import (
	"bytes"
	"fmt"
	"io"
	"os/exec"
	"strings"
	"sync"

	"golang.org/x/crypto/openpgp"
)

type GpgCLI struct {
	path    string
	options []string

	// Configuration --- cache the results
	configured     bool
	configExplicit bool
	configError    error

	mutex *sync.Mutex

	logUI LogUI
}

type GpgCLIArg struct {
	LogUI LogUI // If nil, use the global
}

func NewGpgCLI(arg GpgCLIArg) *GpgCLI {
	logUI := arg.LogUI
	if logUI == nil {
		logUI = G.Log
	}
	return &GpgCLI{
		configured: false,
		mutex:      new(sync.Mutex),
		logUI:      logUI,
	}
}

func (g *GpgCLI) Configure() (configExplicit bool, err error) {

	g.mutex.Lock()
	defer g.mutex.Unlock()

	if g.configured {
		configExplicit = g.configExplicit
		err = g.configError
		return
	}

	prog := G.Env.GetGpg()
	opts := G.Env.GetGpgOptions()

	// If we asked for any explicit GPG options
	configExplicit = (len(prog) > 0 || opts != nil)
	if len(prog) > 0 {
		err = canExec(prog)
	} else {
		prog, err = exec.LookPath("gpg2")
		if err != nil {
			prog, err = exec.LookPath("gpg")
		}
	}

	g.logUI.Debug("| configured GPG w/ path: %s", prog)

	g.path = prog
	g.options = opts
	g.configured = true
	g.configExplicit = configExplicit
	g.configError = err

	return
}

// CanExec returns true if a gpg executable exists.
func (g *GpgCLI) CanExec() (bool, error) {
	if _, err := g.Configure(); err != nil {
		if oerr, ok := err.(*exec.Error); ok {
			if oerr.Err == exec.ErrNotFound {
				return false, nil
			}
		}
		return false, err
	}
	return true, nil
}

// Path returns the path of the gpg executable.  Configure must be
// called before using this.
func (g *GpgCLI) Path() string {
	if !g.configured {
		panic("GpgCLI not configured")
	}
	return g.path
}

type RunGpgArg struct {
	Arguments []string
	Stdin     bool
	Stderr    io.WriteCloser
	Stdout    io.WriteCloser
}

type RunGpgRes struct {
	Stdin io.WriteCloser
	Err   error
	Wait  func() error
}

func (g *GpgCLI) ImportKey(secret bool, fp PGPFingerprint) (ret *PGPKeyBundle, err error) {
	var cmd string
	var which string
	if secret {
		which = "secret"
		cmd = "--export-secret-key"
	} else {
		which = "public"
		cmd = "--export"
	}

	arg := RunGpg2Arg{
		Arguments: []string{"--armor", cmd, fp.String()},
		Stdout:    true,
	}

	res := g.Run2(arg)
	if res.Err != nil {
		return nil, res.Err
	}

	buf := new(bytes.Buffer)
	buf.ReadFrom(res.Stdout)
	armored := buf.String()

	el, err := openpgp.ReadArmoredKeyRing(strings.NewReader(armored))
	if err != nil {
		return nil, err
	}
	if err = res.Wait(); err != nil {
		return nil, err
	}
	if len(el) == 0 {
		return nil, NoKeyError{fmt.Sprintf("No %s key for %s found", which, fp.ToKeyID())}
	}
	if len(el) > 1 {
		return nil, TooManyKeysError{len(el), fp}
	}

	bundle := PGPKeyBundle{el[0], armored}
	return &bundle, nil
{'fraction_non_alphanumeric': 0.13465023559260603, 'fraction_numerical': 0.002899601304820587, 'mean_word_length': 3.0760709010339733, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1414204', 'n_tokens_mistral': 2289, 'n_tokens_neox': 2159, 'n_words': 600}