<commit_before>// Copyright 2014 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package keystore implements the ACI keystore.
package keystore

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
	"github.com/coreos/rkt/Godeps/_workspace/src/golang.org/x/crypto/openpgp"
	"github.com/coreos/rkt/common"
)

// A Config structure is used to configure a Keystore.
type Config struct {
	LocalRootPath    string
	LocalPrefixPath  string
	SystemRootPath   string
	SystemPrefixPath string
}

// A Keystore represents a repository of trusted public keys which can be
// used to verify PGP signatures.
type Keystore struct {
	*Config
}

// New returns a new Keystore based on config.
func New(config *Config) *Keystore {
	if config == nil {
		config = defaultConfig
	}
	return &Keystore{config}
}

func NewConfig(systemPath, localPath string) *Config {
	return &Config{
		LocalRootPath:    filepath.Join(localPath, "trustedkeys", "root.d"),
		LocalPrefixPath:  filepath.Join(localPath, "trustedkeys", "prefix.d"),
		SystemRootPath:   filepath.Join(systemPath, "trustedkeys", "root.d"),
		SystemPrefixPath: filepath.Join(systemPath, "trustedkeys", "prefix.d"),
	}
}

var defaultConfig = NewConfig(common.DefaultSystemConfigDir, common.DefaultLocalConfigDir)

// CheckSignature is a convenience method for creating a Keystore with a default
// configuration and invoking CheckSignature.
func CheckSignature(prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
	ks := New(defaultConfig)
	return checkSignature(ks, prefix, signed, signature)
}

// CheckSignature takes a signed file and a detached signature and returns the signer
// if the signature is signed by a trusted signer.
// If the signer is unknown or not trusted, opengpg.ErrUnknownIssuer is returned.
func (ks *Keystore) CheckSignature(prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
	return checkSignature(ks, prefix, signed, signature)
}

func checkSignature(ks *Keystore, prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return nil, err
	}
	keyring, err := ks.loadKeyring(acidentifier.String())
	if err != nil {
		return nil, fmt.Errorf("keystore: error loading keyring %v", err)
	}
	entities, err := openpgp.CheckArmoredDetachedSignature(keyring, signed, signature)
	if err == io.EOF {
		// When the signature is binary instead of armored, the error is io.EOF.
		// Let's try with binary signatures as well
		if _, err := signed.Seek(0, 0); err != nil {
			return nil, fmt.Errorf("error seeking ACI file: %v", err)
		}
		if _, err := signature.Seek(0, 0); err != nil {
			return nil, fmt.Errorf("error seeking signature file: %v", err)
		}
		entities, err = openpgp.CheckDetachedSignature(keyring, signed, signature)
	}
	if err == io.EOF {
		// otherwise, the client failure is just "EOF", which is not helpful
		return nil, fmt.Errorf("keystore: no valid signatures found in signature file")
	}
	return entities, err
}

// DeleteTrustedKeyPrefix deletes the prefix trusted key identified by fingerprint.
func (ks *Keystore) DeleteTrustedKeyPrefix(prefix, fingerprint string) error {
	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return err
	}
	return os.Remove(path.Join(ks.LocalPrefixPath, acidentifier.String(), fingerprint))
}

// MaskTrustedKeySystemPrefix masks the system prefix trusted key identified by fingerprint.
func (ks *Keystore) MaskTrustedKeySystemPrefix(prefix, fingerprint string) (string, error) {
	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return "", err
	}
	dst := path.Join(ks.LocalPrefixPath, acidentifier.String(), fingerprint)
	return dst, ioutil.WriteFile(dst, []byte(""), 0644)
}

// DeleteTrustedKeyRoot deletes the root trusted key identified by fingerprint.
func (ks *Keystore) DeleteTrustedKeyRoot(fingerprint string) error {
	return os.Remove(path.Join(ks.LocalRootPath, fingerprint))
}

// MaskTrustedKeySystemRoot masks the system root trusted key identified by fingerprint.
func (ks *Keystore) MaskTrustedKeySystemRoot(fingerprint string) (string, error) {
	dst := path.Join(ks.LocalRootPath, fingerprint)
	return dst, ioutil.WriteFile(dst, []byte(""), 0644)
}

func (ks *Keystore) TrustedKeyPrefixExists(prefix string, r io.ReadSeeker) (bool, error) {
	defer r.Seek(0, os.SEEK_SET)

	entityList, err := openpgp.ReadArmoredKeyRing(r)
	if err != nil {
		return false, err
	}
	if len(entityList) < 1 {
		return false, errors.New("missing opengpg entity")
	}
	pubKey := entityList[0].PrimaryKey
	fileName := fingerprintToFilename(pubKey.Fingerprint)

	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return false, err
	}

	pathNames := []string{
		// example: /etc/rkt/trustedkeys/prefix.d/coreos.com/etcd/<KEY>
		path.Join(ks.LocalPrefixPath, acidentifier.String(), fileName),
		// example: /usr/lib/rkt/trustedkeys/prefix.d/coreos.com/etcd/<KEY>0
		path.Join(ks.SystemPrefixPath, acidentifier.String(), fileName),
		// example: /etc/rkt/trustedkeys/root.d/<KEY>
		path.Join(ks.LocalRootPath, fileName),
		// example: /usr/lib/rkt/trustedkeys/root.d/8b86de38890ddb7291867b025210bd8888182190
		path.Join(ks.SystemRootPath, fileName),
	}
	for _, p := range pathNames {
		_, err := os.Stat(p)
		if err == nil {
			return true, nil
		} else if !os.IsNotExist(err) {
			return false, fmt.Errorf("cannot check file %q: %v", p, err)
		}
	}<commit_msg>trust: fix regression on --root<commit_after>// Copyright 2014 The rkt Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package keystore implements the ACI keystore.
package keystore

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
	"github.com/coreos/rkt/Godeps/_workspace/src/golang.org/x/crypto/openpgp"
	"github.com/coreos/rkt/common"
)

// A Config structure is used to configure a Keystore.
type Config struct {
	LocalRootPath    string
	LocalPrefixPath  string
	SystemRootPath   string
	SystemPrefixPath string
}

// A Keystore represents a repository of trusted public keys which can be
// used to verify PGP signatures.
type Keystore struct {
	*Config
}

// New returns a new Keystore based on config.
func New(config *Config) *Keystore {
	if config == nil {
		config = defaultConfig
	}
	return &Keystore{config}
}

func NewConfig(systemPath, localPath string) *Config {
	return &Config{
		LocalRootPath:    filepath.Join(localPath, "trustedkeys", "root.d"),
		LocalPrefixPath:  filepath.Join(localPath, "trustedkeys", "prefix.d"),
		SystemRootPath:   filepath.Join(systemPath, "trustedkeys", "root.d"),
		SystemPrefixPath: filepath.Join(systemPath, "trustedkeys", "prefix.d"),
	}
}

var defaultConfig = NewConfig(common.DefaultSystemConfigDir, common.DefaultLocalConfigDir)

// CheckSignature is a convenience method for creating a Keystore with a default
// configuration and invoking CheckSignature.
func CheckSignature(prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
	ks := New(defaultConfig)
	return checkSignature(ks, prefix, signed, signature)
}

// CheckSignature takes a signed file and a detached signature and returns the signer
// if the signature is signed by a trusted signer.
// If the signer is unknown or not trusted, opengpg.ErrUnknownIssuer is returned.
func (ks *Keystore) CheckSignature(prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
	return checkSignature(ks, prefix, signed, signature)
}

func checkSignature(ks *Keystore, prefix string, signed, signature io.ReadSeeker) (*openpgp.Entity, error) {
	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return nil, err
	}
	keyring, err := ks.loadKeyring(acidentifier.String())
	if err != nil {
		return nil, fmt.Errorf("keystore: error loading keyring %v", err)
	}
	entities, err := openpgp.CheckArmoredDetachedSignature(keyring, signed, signature)
	if err == io.EOF {
		// When the signature is binary instead of armored, the error is io.EOF.
		// Let's try with binary signatures as well
		if _, err := signed.Seek(0, 0); err != nil {
			return nil, fmt.Errorf("error seeking ACI file: %v", err)
		}
		if _, err := signature.Seek(0, 0); err != nil {
			return nil, fmt.Errorf("error seeking signature file: %v", err)
		}
		entities, err = openpgp.CheckDetachedSignature(keyring, signed, signature)
	}
	if err == io.EOF {
		// otherwise, the client failure is just "EOF", which is not helpful
		return nil, fmt.Errorf("keystore: no valid signatures found in signature file")
	}
	return entities, err
}

// DeleteTrustedKeyPrefix deletes the prefix trusted key identified by fingerprint.
func (ks *Keystore) DeleteTrustedKeyPrefix(prefix, fingerprint string) error {
	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return err
	}
	return os.Remove(path.Join(ks.LocalPrefixPath, acidentifier.String(), fingerprint))
}

// MaskTrustedKeySystemPrefix masks the system prefix trusted key identified by fingerprint.
func (ks *Keystore) MaskTrustedKeySystemPrefix(prefix, fingerprint string) (string, error) {
	acidentifier, err := types.NewACIdentifier(prefix)
	if err != nil {
		return "", err
	}
	dst := path.Join(ks.LocalPrefixPath, acidentifier.String(), fingerprint)
	return dst, ioutil.WriteFile(dst, []byte(""), 0644)
}

// DeleteTrustedKeyRoot deletes the root trusted key identified by fingerprint.
func (ks *Keystore) DeleteTrustedKeyRoot(fingerprint string) error {
	return os.Remove(path.Join(ks.LocalRootPath, fingerprint))
}

// MaskTrustedKeySystemRoot masks the system root trusted key identified by fingerprint.
func (ks *Keystore) MaskTrustedKeySystemRoot(fingerprint string) (string, error) {
	dst := path.Join(ks.LocalRootPath, fingerprint)
	return dst, ioutil.WriteFile(dst, []byte(""), 0644)
}

func (ks *Keystore) TrustedKeyPrefixExists(prefix string, r io.ReadSeeker) (bool, error) {
	defer r.Seek(0, os.SEEK_SET)

	entityList, err := openpgp.ReadArmoredKeyRing(r)
	if err != nil {
		return false, err
	}
	if len(entityList) < 1 {
		return false, errors.New("missing opengpg entity")
	}
	pubKey := entityList[0].PrimaryKey
	fileName := fingerprintToFilename(pubKey.Fingerprint)

	pathNamesRoot := []string{
		// example: /etc/rkt/trustedkeys/root.d/8b86de38890ddb7291867b025210bd8888182190
		path.Join(ks.LocalRootPath, fileName),
		// example: /usr/lib/rkt/trustedkeys/root.d/8b86de38890ddb7291867b025210bd8888182190
		path.Join(ks.SystemRootPath, fileName),
	}

	var pathNamesPrefix []string
	if prefix != "" {
		acidentifier, err := types.NewACIdentifier(prefix)
		if err != nil {
			return false, err
		}
		pathNamesPrefix = []string{
			// example: /etc/rkt/trustedkeys/prefix.d/coreos.com/etcd/8b86de38890ddb7291867b025210bd8888182190
			path.Join(ks.LocalPrefixPath, acidentifier.String(), fileName),
			// example: /usr/lib/rkt/trustedkeys/prefix.d/coreos.com/etcd/8b86de38890ddb7291867b025210bd8888182190
			path.Join(ks.SystemPrefixPath, acidentifier.String(), fileName),
		}
	}

	pathNames := append(pathNamesRoot, pathNamesPrefix...)
	for _, p := range pathNames {
		_, err := os.Stat(p)
		if err == nil {
			return true, nil
		} else if !os.IsNotExist(err) {
			return false, fmt.Errorf("cannot check file %q: %v", p, err)
		}
	}
{'fraction_non_alphanumeric': 0.11490757781867648, 'fraction_numerical': 0.01616387933103945, 'mean_word_length': 4.530088495575221, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '1844752', 'n_tokens_mistral': 4251, 'n_tokens_neox': 3946, 'n_words': 1180}