зеркало из https://github.com/getsops/sops.git
Merge pull request #491 from adrianosela/golint
Address Go Lint messages
This commit is contained in:
Коммит
9998e16c3e
|
@ -45,6 +45,7 @@ type Cipher struct {
|
||||||
stash map[stashKey][]byte
|
stash map[stashKey][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCipher is the constructor for a new Cipher object
|
||||||
func NewCipher() Cipher {
|
func NewCipher() Cipher {
|
||||||
return Cipher{
|
return Cipher{
|
||||||
stash: make(map[stashKey][]byte),
|
stash: make(map[stashKey][]byte),
|
||||||
|
|
|
@ -9,7 +9,9 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
// empty import as per https://godoc.org/github.com/lib/pq
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"go.mozilla.org/sops/logging"
|
"go.mozilla.org/sops/logging"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
@ -67,36 +69,52 @@ type config struct {
|
||||||
|
|
||||||
var auditors []Auditor
|
var auditors []Auditor
|
||||||
|
|
||||||
|
// SubmitEvent handles an event for all auditors
|
||||||
func SubmitEvent(event interface{}) {
|
func SubmitEvent(event interface{}) {
|
||||||
for _, auditor := range auditors {
|
for _, auditor := range auditors {
|
||||||
auditor.Handle(event)
|
auditor.Handle(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register registers a new Auditor in the global auditor list
|
||||||
func Register(auditor Auditor) {
|
func Register(auditor Auditor) {
|
||||||
auditors = append(auditors, auditor)
|
auditors = append(auditors, auditor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auditor is notified when noteworthy events happen,
|
||||||
|
// for example when a file is encrypted or decrypted.
|
||||||
type Auditor interface {
|
type Auditor interface {
|
||||||
|
// Handle() takes an audit event and attempts to persists it;
|
||||||
|
// how it is persisted and how errors are handled is up to the
|
||||||
|
// implementation of this interface.
|
||||||
Handle(event interface{})
|
Handle(event interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecryptEvent contains fields relevant to a decryption event
|
||||||
type DecryptEvent struct {
|
type DecryptEvent struct {
|
||||||
File string
|
File string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncryptEvent contains fields relevant to an encryption event
|
||||||
type EncryptEvent struct {
|
type EncryptEvent struct {
|
||||||
File string
|
File string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RotateEvent contains fields relevant to a key rotation event
|
||||||
type RotateEvent struct {
|
type RotateEvent struct {
|
||||||
File string
|
File string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PostgresAuditor is a Postgres SQL DB implementation of the Auditor interface.
|
||||||
|
// It persists the audit event by writing a row to the 'audit_event' table.
|
||||||
|
// Errors with writing to the database will output a log message and the
|
||||||
|
// process will exit with status set to 1
|
||||||
type PostgresAuditor struct {
|
type PostgresAuditor struct {
|
||||||
DB *sql.DB
|
DB *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPostgresAuditor is the constructor for a new PostgresAuditor struct
|
||||||
|
// initialized with the given db connection string
|
||||||
func NewPostgresAuditor(connStr string) (*PostgresAuditor, error) {
|
func NewPostgresAuditor(connStr string) (*PostgresAuditor, error) {
|
||||||
db, err := sql.Open("postgres", connStr)
|
db, err := sql.Open("postgres", connStr)
|
||||||
pg := &PostgresAuditor{DB: db}
|
pg := &PostgresAuditor{DB: db}
|
||||||
|
@ -113,6 +131,8 @@ func NewPostgresAuditor(connStr string) (*PostgresAuditor, error) {
|
||||||
return pg, nil
|
return pg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle persists the audit event by writing a row to the
|
||||||
|
// 'audit_event' postgres table
|
||||||
func (p *PostgresAuditor) Handle(event interface{}) {
|
func (p *PostgresAuditor) Handle(event interface{}) {
|
||||||
u, err := user.Current()
|
u, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -73,7 +73,7 @@ func MasterKeysFromURLs(urls string) ([]*MasterKey, error) {
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMasterKeyFromResourceID takes an Azure Key Vault key URL and returns a new MasterKey
|
// NewMasterKeyFromURL takes an Azure Key Vault key URL and returns a new MasterKey
|
||||||
// URL format is {vaultUrl}/keys/{key-name}/{key-version}
|
// URL format is {vaultUrl}/keys/{key-name}/{key-version}
|
||||||
func NewMasterKeyFromURL(url string) (*MasterKey, error) {
|
func NewMasterKeyFromURL(url string) (*MasterKey, error) {
|
||||||
k := &MasterKey{}
|
k := &MasterKey{}
|
||||||
|
|
|
@ -92,16 +92,16 @@ func TestKeyToMap(t *testing.T) {
|
||||||
}, key.ToMap())
|
}, key.ToMap())
|
||||||
}
|
}
|
||||||
|
|
||||||
var azureKeyAcceptanceTestUrl = flag.String("azure-key", "", "URL to Azure Key Vault (note that this can incur real costs!)")
|
var azureKeyAcceptanceTestURL = flag.String("azure-key", "", "URL to Azure Key Vault (note that this can incur real costs!)")
|
||||||
|
|
||||||
func TestRoundtrip(t *testing.T) {
|
func TestRoundtrip(t *testing.T) {
|
||||||
if *azureKeyAcceptanceTestUrl == "" {
|
if *azureKeyAcceptanceTestURL == "" {
|
||||||
t.Skip("Azure URL not provided, skipping acceptance test")
|
t.Skip("Azure URL not provided, skipping acceptance test")
|
||||||
}
|
}
|
||||||
|
|
||||||
input := []byte("test-string")
|
input := []byte("test-string")
|
||||||
|
|
||||||
key, err := NewMasterKeyFromURL(*azureKeyAcceptanceTestUrl)
|
key, err := NewMasterKeyFromURL(*azureKeyAcceptanceTestURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,13 @@ import (
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ExampleFileEmitter emits example files. This is used by the `sops` binary
|
||||||
|
// whenever a new file is created, in order to present the user with a non-empty file
|
||||||
type ExampleFileEmitter interface {
|
type ExampleFileEmitter interface {
|
||||||
EmitExample() []byte
|
EmitExample() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store handles marshaling and unmarshaling from SOPS files
|
||||||
type Store interface {
|
type Store interface {
|
||||||
sops.Store
|
sops.Store
|
||||||
ExampleFileEmitter
|
ExampleFileEmitter
|
||||||
|
@ -107,6 +110,8 @@ func LoadEncryptedFile(loader sops.EncryptedFileLoader, inputPath string) (*sops
|
||||||
return &tree, err
|
return &tree, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewExitError returns a cli.ExitError given an error (wrapped in a generic interface{})
|
||||||
|
// and an exit code to represent the failure
|
||||||
func NewExitError(i interface{}, exitCode int) *cli.ExitError {
|
func NewExitError(i interface{}, exitCode int) *cli.ExitError {
|
||||||
if userErr, ok := i.(sops.UserError); ok {
|
if userErr, ok := i.(sops.UserError); ok {
|
||||||
return NewExitError(userErr.UserError(), exitCode)
|
return NewExitError(userErr.UserError(), exitCode)
|
||||||
|
@ -114,22 +119,28 @@ func NewExitError(i interface{}, exitCode int) *cli.ExitError {
|
||||||
return cli.NewExitError(i, exitCode)
|
return cli.NewExitError(i, exitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsYAMLFile returns true if a given file path corresponds to a YAML file
|
||||||
func IsYAMLFile(path string) bool {
|
func IsYAMLFile(path string) bool {
|
||||||
return strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")
|
return strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsJSONFile returns true if a given file path corresponds to a JSON file
|
||||||
func IsJSONFile(path string) bool {
|
func IsJSONFile(path string) bool {
|
||||||
return strings.HasSuffix(path, ".json")
|
return strings.HasSuffix(path, ".json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsEnvFile returns true if a given file path corresponds to a .env file
|
||||||
func IsEnvFile(path string) bool {
|
func IsEnvFile(path string) bool {
|
||||||
return strings.HasSuffix(path, ".env")
|
return strings.HasSuffix(path, ".env")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsIniFile returns true if a given file path corresponds to a INI file
|
||||||
func IsIniFile(path string) bool {
|
func IsIniFile(path string) bool {
|
||||||
return strings.HasSuffix(path, ".ini")
|
return strings.HasSuffix(path, ".ini")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultStoreForPath returns the correct format-specific implementation
|
||||||
|
// of the Store interface given the path to a file
|
||||||
func DefaultStoreForPath(path string) Store {
|
func DefaultStoreForPath(path string) Store {
|
||||||
if IsYAMLFile(path) {
|
if IsYAMLFile(path) {
|
||||||
return &yaml.Store{}
|
return &yaml.Store{}
|
||||||
|
@ -143,8 +154,12 @@ func DefaultStoreForPath(path string) Store {
|
||||||
return &json.BinaryStore{}
|
return &json.BinaryStore{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// KMS_ENC_CTX_BUG_FIXED_VERSION represents the SOPS version in which the
|
||||||
|
// encryption context bug was fixed
|
||||||
const KMS_ENC_CTX_BUG_FIXED_VERSION = "3.3.0"
|
const KMS_ENC_CTX_BUG_FIXED_VERSION = "3.3.0"
|
||||||
|
|
||||||
|
// DetectKMSEncryptionContextBug returns true if the encryption context bug is detected
|
||||||
|
// in a given runtime sops.Tree object
|
||||||
func DetectKMSEncryptionContextBug(tree *sops.Tree) (bool, error) {
|
func DetectKMSEncryptionContextBug(tree *sops.Tree) (bool, error) {
|
||||||
versionCheck, err := version.AIsNewerThanB(KMS_ENC_CTX_BUG_FIXED_VERSION, tree.Metadata.Version)
|
versionCheck, err := version.AIsNewerThanB(KMS_ENC_CTX_BUG_FIXED_VERSION, tree.Metadata.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -161,6 +176,7 @@ func DetectKMSEncryptionContextBug(tree *sops.Tree) (bool, error) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetKMSKeyWithEncryptionCtx returns the first KMS key affected by the encryption context bug as well as its location in the key groups.
|
||||||
func GetKMSKeyWithEncryptionCtx(tree *sops.Tree) (keyGroupIndex int, keyIndex int, key *kms.MasterKey) {
|
func GetKMSKeyWithEncryptionCtx(tree *sops.Tree) (keyGroupIndex int, keyIndex int, key *kms.MasterKey) {
|
||||||
for i, kg := range tree.Metadata.KeyGroups {
|
for i, kg := range tree.Metadata.KeyGroups {
|
||||||
for n, k := range kg {
|
for n, k := range kg {
|
||||||
|
@ -181,6 +197,7 @@ func GetKMSKeyWithEncryptionCtx(tree *sops.Tree) (keyGroupIndex int, keyIndex in
|
||||||
return 0, 0, nil
|
return 0, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenericDecryptOpts represents decryption options and config
|
||||||
type GenericDecryptOpts struct {
|
type GenericDecryptOpts struct {
|
||||||
Cipher sops.Cipher
|
Cipher sops.Cipher
|
||||||
InputStore sops.Store
|
InputStore sops.Store
|
||||||
|
@ -235,10 +252,9 @@ func FixAWSKMSEncryptionContextBug(opts GenericDecryptOpts, tree *sops.Tree) (*s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if response == "n" {
|
if response == "n" {
|
||||||
return nil, fmt.Errorf("Exiting. User responded no.")
|
return nil, fmt.Errorf("Exiting. User responded no")
|
||||||
} else {
|
|
||||||
persistFix = true
|
|
||||||
}
|
}
|
||||||
|
persistFix = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is another key, then we should be able to just decrypt
|
// If there is another key, then we should be able to just decrypt
|
||||||
|
@ -341,6 +357,7 @@ func RecoverDataKeyFromBuggyKMS(opts GenericDecryptOpts, tree *sops.Tree) []byte
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diff represents a key diff
|
||||||
type Diff struct {
|
type Diff struct {
|
||||||
Common []keys.MasterKey
|
Common []keys.MasterKey
|
||||||
Added []keys.MasterKey
|
Added []keys.MasterKey
|
||||||
|
@ -354,6 +371,7 @@ func max(a, b int) int {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DiffKeyGroups returns the list of diffs found in two sops.keyGroup slices
|
||||||
func DiffKeyGroups(ours, theirs []sops.KeyGroup) []Diff {
|
func DiffKeyGroups(ours, theirs []sops.KeyGroup) []Diff {
|
||||||
var diffs []Diff
|
var diffs []Diff
|
||||||
for i := 0; i < max(len(ours), len(theirs)); i++ {
|
for i := 0; i < max(len(ours), len(theirs)); i++ {
|
||||||
|
@ -388,6 +406,7 @@ func DiffKeyGroups(ours, theirs []sops.KeyGroup) []Diff {
|
||||||
return diffs
|
return diffs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrettyPrintDiffs prints a slice of Diff objects to stdout
|
||||||
func PrettyPrintDiffs(diffs []Diff) {
|
func PrettyPrintDiffs(diffs []Diff) {
|
||||||
for i, diff := range diffs {
|
for i, diff := range diffs {
|
||||||
color.New(color.Underline).Printf("Group %d\n", i+1)
|
color.New(color.Underline).Printf("Group %d\n", i+1)
|
||||||
|
|
|
@ -24,6 +24,7 @@ func init() {
|
||||||
log = logging.NewLogger("PUBLISH")
|
log = logging.NewLogger("PUBLISH")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opts represents publish options and config
|
||||||
type Opts struct {
|
type Opts struct {
|
||||||
Interactive bool
|
Interactive bool
|
||||||
Cipher sops.Cipher
|
Cipher sops.Cipher
|
||||||
|
@ -33,6 +34,7 @@ type Opts struct {
|
||||||
InputStore sops.Store
|
InputStore sops.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run publish operation
|
||||||
func Run(opts Opts) error {
|
func Run(opts Opts) error {
|
||||||
var fileContents []byte
|
var fileContents []byte
|
||||||
path, err := filepath.Abs(opts.InputPath)
|
path, err := filepath.Abs(opts.InputPath)
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"go.mozilla.org/sops/keyservice"
|
"go.mozilla.org/sops/keyservice"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Opts represents key operation options and config
|
||||||
type Opts struct {
|
type Opts struct {
|
||||||
InputPath string
|
InputPath string
|
||||||
GroupQuorum int
|
GroupQuorum int
|
||||||
|
@ -20,6 +21,7 @@ type Opts struct {
|
||||||
ConfigPath string
|
ConfigPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateKeys update the keys for a given file
|
||||||
func UpdateKeys(opts Opts) error {
|
func UpdateKeys(opts Opts) error {
|
||||||
path, err := filepath.Abs(opts.InputPath)
|
path, err := filepath.Abs(opts.InputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -17,12 +17,14 @@ type TextFormatter struct {
|
||||||
logrus.TextFormatter
|
logrus.TextFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format formats a log entry onto bytes
|
||||||
func (f *TextFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
func (f *TextFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||||
bytes, err := f.TextFormatter.Format(entry)
|
bytes, err := f.TextFormatter.Format(entry)
|
||||||
name := color.New(color.Bold).Sprintf("[%s]", f.LoggerName)
|
name := color.New(color.Bold).Sprintf("[%s]", f.LoggerName)
|
||||||
return []byte(fmt.Sprintf("%s\t %s", name, bytes)), err
|
return []byte(fmt.Sprintf("%s\t %s", name, bytes)), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewLogger is the constructor for a new Logger object with the given name
|
||||||
func NewLogger(name string) *logrus.Logger {
|
func NewLogger(name string) *logrus.Logger {
|
||||||
log := logrus.New()
|
log := logrus.New()
|
||||||
log.SetLevel(logrus.WarnLevel)
|
log.SetLevel(logrus.WarnLevel)
|
||||||
|
@ -33,10 +35,12 @@ func NewLogger(name string) *logrus.Logger {
|
||||||
return log
|
return log
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLevel sets the given level for all current Loggers
|
||||||
func SetLevel(level logrus.Level) {
|
func SetLevel(level logrus.Level) {
|
||||||
for k := range Loggers {
|
for k := range Loggers {
|
||||||
Loggers[k].SetLevel(level)
|
Loggers[k].SetLevel(level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Loggers is the runtime map of logger name to logger object
|
||||||
var Loggers map[string]*logrus.Logger
|
var Loggers map[string]*logrus.Logger
|
||||||
|
|
|
@ -7,19 +7,23 @@ import (
|
||||||
"cloud.google.com/go/storage"
|
"cloud.google.com/go/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GCSDestination represents the Google Cloud Storage destination
|
||||||
type GCSDestination struct {
|
type GCSDestination struct {
|
||||||
gcsBucket string
|
gcsBucket string
|
||||||
gcsPrefix string
|
gcsPrefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewGCSDestination is the constructor for a Google Cloud Storage destination
|
||||||
func NewGCSDestination(gcsBucket string, gcsPrefix string) *GCSDestination {
|
func NewGCSDestination(gcsBucket string, gcsPrefix string) *GCSDestination {
|
||||||
return &GCSDestination{gcsBucket, gcsPrefix}
|
return &GCSDestination{gcsBucket, gcsPrefix}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Path returns a the GCS path for a file within this GCS Destination
|
||||||
func (gcsd *GCSDestination) Path(fileName string) string {
|
func (gcsd *GCSDestination) Path(fileName string) string {
|
||||||
return fmt.Sprintf("gcs://%s/%s%s", gcsd.gcsBucket, gcsd.gcsPrefix, fileName)
|
return fmt.Sprintf("gcs://%s/%s%s", gcsd.gcsBucket, gcsd.gcsPrefix, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upload uploads contents to a file in GCS
|
||||||
func (gcsd *GCSDestination) Upload(fileContents []byte, fileName string) error {
|
func (gcsd *GCSDestination) Upload(fileContents []byte, fileName string) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
client, err := storage.NewClient(ctx)
|
client, err := storage.NewClient(ctx)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package publish
|
package publish
|
||||||
|
|
||||||
|
// Destination represents actions which all destination types
|
||||||
|
// must implement in order to be used by SOPS
|
||||||
type Destination interface {
|
type Destination interface {
|
||||||
Upload(fileContents []byte, fileName string) error
|
Upload(fileContents []byte, fileName string) error
|
||||||
Path(fileName string) string
|
Path(fileName string) string
|
||||||
|
|
|
@ -9,19 +9,23 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// S3Destination is the AWS S3 implementation of the Destination interface
|
||||||
type S3Destination struct {
|
type S3Destination struct {
|
||||||
s3Bucket string
|
s3Bucket string
|
||||||
s3Prefix string
|
s3Prefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewS3Destination is the constructor for an S3 Destination
|
||||||
func NewS3Destination(s3Bucket string, s3Prefix string) *S3Destination {
|
func NewS3Destination(s3Bucket string, s3Prefix string) *S3Destination {
|
||||||
return &S3Destination{s3Bucket, s3Prefix}
|
return &S3Destination{s3Bucket, s3Prefix}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Path returns the S3 path of a file in an S3 Destination (bucket)
|
||||||
func (s3d *S3Destination) Path(fileName string) string {
|
func (s3d *S3Destination) Path(fileName string) string {
|
||||||
return fmt.Sprintf("s3://%s/%s%s", s3d.s3Bucket, s3d.s3Prefix, fileName)
|
return fmt.Sprintf("s3://%s/%s%s", s3d.s3Bucket, s3d.s3Prefix, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upload uploads contents to a file in an S3 Destination (bucket)
|
||||||
func (s3d *S3Destination) Upload(fileContents []byte, fileName string) error {
|
func (s3d *S3Destination) Upload(fileContents []byte, fileName string) error {
|
||||||
sess := session.Must(session.NewSession())
|
sess := session.Must(session.NewSession())
|
||||||
svc := s3.New(sess)
|
svc := s3.New(sess)
|
||||||
|
|
|
@ -73,8 +73,8 @@ func (p *polynomial) evaluate(x uint8) uint8 {
|
||||||
// An implementation of Lagrange interpolation
|
// An implementation of Lagrange interpolation
|
||||||
// <https://en.wikipedia.org/wiki/Lagrange_polynomial>
|
// <https://en.wikipedia.org/wiki/Lagrange_polynomial>
|
||||||
// For this particular implementation, x is always 0
|
// For this particular implementation, x is always 0
|
||||||
func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 {
|
func interpolatePolynomial(xSamples, ySamples []uint8, x uint8) uint8 {
|
||||||
limit := len(x_samples)
|
limit := len(xSamples)
|
||||||
var result, basis uint8
|
var result, basis uint8
|
||||||
for i := 0; i < limit; i++ {
|
for i := 0; i < limit; i++ {
|
||||||
basis = 1
|
basis = 1
|
||||||
|
@ -82,12 +82,12 @@ func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 {
|
||||||
if i == j {
|
if i == j {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
num := add(x, x_samples[j])
|
num := add(x, xSamples[j])
|
||||||
denom := add(x_samples[i], x_samples[j])
|
denom := add(xSamples[i], xSamples[j])
|
||||||
term := div(num, denom)
|
term := div(num, denom)
|
||||||
basis = mult(basis, term)
|
basis = mult(basis, term)
|
||||||
}
|
}
|
||||||
group := mult(y_samples[i], basis)
|
group := mult(ySamples[i], basis)
|
||||||
result = add(result, group)
|
result = add(result, group)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
@ -103,9 +103,9 @@ func div(a, b uint8) uint8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
var goodVal, zero uint8
|
var goodVal, zero uint8
|
||||||
log_a := logTable[a]
|
logA := logTable[a]
|
||||||
log_b := logTable[b]
|
logB := logTable[b]
|
||||||
diff := (int(log_a) - int(log_b)) % 255
|
diff := (int(logA) - int(logB)) % 255
|
||||||
if diff < 0 {
|
if diff < 0 {
|
||||||
diff += 255
|
diff += 255
|
||||||
}
|
}
|
||||||
|
@ -258,8 +258,8 @@ func Combine(parts [][]byte) ([]byte, error) {
|
||||||
secret := make([]byte, firstPartLen-1)
|
secret := make([]byte, firstPartLen-1)
|
||||||
|
|
||||||
// Buffer to store the samples
|
// Buffer to store the samples
|
||||||
x_samples := make([]uint8, len(parts))
|
xSamples := make([]uint8, len(parts))
|
||||||
y_samples := make([]uint8, len(parts))
|
ySamples := make([]uint8, len(parts))
|
||||||
|
|
||||||
// Set the x value for each sample and ensure no x_sample values are the same,
|
// Set the x value for each sample and ensure no x_sample values are the same,
|
||||||
// otherwise div() can be unhappy
|
// otherwise div() can be unhappy
|
||||||
|
@ -272,19 +272,19 @@ func Combine(parts [][]byte) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("duplicate part detected")
|
return nil, fmt.Errorf("duplicate part detected")
|
||||||
}
|
}
|
||||||
checkMap[samp] = true
|
checkMap[samp] = true
|
||||||
x_samples[i] = samp
|
xSamples[i] = samp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconstruct each byte
|
// Reconstruct each byte
|
||||||
for idx := range secret {
|
for idx := range secret {
|
||||||
// Set the y value for each sample
|
// Set the y value for each sample
|
||||||
for i, part := range parts {
|
for i, part := range parts {
|
||||||
y_samples[i] = part[idx]
|
ySamples[i] = part[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Lagrange interpolation to retrieve the free term
|
// Use Lagrange interpolation to retrieve the free term
|
||||||
// of the original polynomial
|
// of the original polynomial
|
||||||
val := interpolatePolynomial(x_samples, y_samples, 0)
|
val := interpolatePolynomial(xSamples, ySamples, 0)
|
||||||
|
|
||||||
// Evaluate the 0th value to get the intercept
|
// Evaluate the 0th value to get the intercept
|
||||||
secret[idx] = val
|
secret[idx] = val
|
||||||
|
|
|
@ -188,9 +188,9 @@ func TestInterpolate_Rand(t *testing.T) {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
x_vals := []uint8{1, 2, 3}
|
xVals := []uint8{1, 2, 3}
|
||||||
y_vals := []uint8{p.evaluate(1), p.evaluate(2), p.evaluate(3)}
|
yVals := []uint8{p.evaluate(1), p.evaluate(2), p.evaluate(3)}
|
||||||
out := interpolatePolynomial(x_vals, y_vals, 0)
|
out := interpolatePolynomial(xVals, yVals, 0)
|
||||||
if out != uint8(i) {
|
if out != uint8(i) {
|
||||||
t.Fatalf("Bad: %v %d", out, i)
|
t.Fatalf("Bad: %v %d", out, i)
|
||||||
}
|
}
|
||||||
|
|
38
sops.go
38
sops.go
|
@ -100,6 +100,7 @@ type TreeItem struct {
|
||||||
// TreeBranch is a branch inside sops's tree. It is a slice of TreeItems and is therefore ordered
|
// TreeBranch is a branch inside sops's tree. It is a slice of TreeItems and is therefore ordered
|
||||||
type TreeBranch []TreeItem
|
type TreeBranch []TreeItem
|
||||||
|
|
||||||
|
// TreeBranches is a collection of TreeBranch
|
||||||
// Trees usually have more than one branch
|
// Trees usually have more than one branch
|
||||||
type TreeBranches []TreeBranch
|
type TreeBranches []TreeBranch
|
||||||
|
|
||||||
|
@ -110,10 +111,9 @@ func valueFromPathAndLeaf(path []interface{}, leaf interface{}) interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
leaf,
|
leaf,
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
valueFromPathAndLeaf(path[1:], leaf),
|
valueFromPathAndLeaf(path[1:], leaf),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if len(path) == 1 {
|
if len(path) == 1 {
|
||||||
|
@ -123,13 +123,12 @@ func valueFromPathAndLeaf(path []interface{}, leaf interface{}) interface{} {
|
||||||
Value: leaf,
|
Value: leaf,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return TreeBranch{
|
return TreeBranch{
|
||||||
TreeItem{
|
TreeItem{
|
||||||
Key: component,
|
Key: component,
|
||||||
Value: valueFromPathAndLeaf(path[1:], leaf),
|
Value: valueFromPathAndLeaf(path[1:], leaf),
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,31 +149,28 @@ func set(branch interface{}, path []interface{}, value interface{}) interface{}
|
||||||
// Not found, need to add the next path entry to the branch
|
// Not found, need to add the next path entry to the branch
|
||||||
if len(path) == 1 {
|
if len(path) == 1 {
|
||||||
return append(branch, TreeItem{Key: path[0], Value: value})
|
return append(branch, TreeItem{Key: path[0], Value: value})
|
||||||
} else {
|
|
||||||
return valueFromPathAndLeaf(path, value)
|
|
||||||
}
|
}
|
||||||
|
return valueFromPathAndLeaf(path, value)
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
position := path[0].(int)
|
position := path[0].(int)
|
||||||
if len(path) == 1 {
|
if len(path) == 1 {
|
||||||
if position >= len(branch) {
|
if position >= len(branch) {
|
||||||
return append(branch, value)
|
return append(branch, value)
|
||||||
} else {
|
|
||||||
branch[position] = value
|
|
||||||
}
|
}
|
||||||
return branch
|
branch[position] = value
|
||||||
} else {
|
} else {
|
||||||
if position >= len(branch) {
|
if position >= len(branch) {
|
||||||
branch = append(branch, valueFromPathAndLeaf(path[1:], value))
|
branch = append(branch, valueFromPathAndLeaf(path[1:], value))
|
||||||
} else {
|
|
||||||
branch[position] = set(branch[position], path[1:], value)
|
|
||||||
}
|
}
|
||||||
return branch
|
branch[position] = set(branch[position], path[1:], value)
|
||||||
}
|
}
|
||||||
|
return branch
|
||||||
default:
|
default:
|
||||||
return valueFromPathAndLeaf(path, value)
|
return valueFromPathAndLeaf(path, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set sets a value on a given tree for the specified path
|
||||||
func (branch TreeBranch) Set(path []interface{}, value interface{}) TreeBranch {
|
func (branch TreeBranch) Set(path []interface{}, value interface{}) TreeBranch {
|
||||||
return set(branch, path, value).(TreeBranch)
|
return set(branch, path, value).(TreeBranch)
|
||||||
}
|
}
|
||||||
|
@ -486,6 +482,8 @@ type PlainFileEmitter interface {
|
||||||
EmitPlainFile(TreeBranches) ([]byte, error)
|
EmitPlainFile(TreeBranches) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValueEmitter is the interface for emitting a value. It provides a way to emit
|
||||||
|
// values from the internal SOPS representation so that they can be shown
|
||||||
type ValueEmitter interface {
|
type ValueEmitter interface {
|
||||||
EmitValue(interface{}) ([]byte, error)
|
EmitValue(interface{}) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
@ -634,7 +632,7 @@ func decryptKeyGroup(group KeyGroup, svcs []keyservice.KeyServiceClient) ([]byte
|
||||||
// of the key services, returning as soon as one key service succeeds.
|
// of the key services, returning as soon as one key service succeeds.
|
||||||
func decryptKey(key keys.MasterKey, svcs []keyservice.KeyServiceClient) ([]byte, error) {
|
func decryptKey(key keys.MasterKey, svcs []keyservice.KeyServiceClient) ([]byte, error) {
|
||||||
svcKey := keyservice.KeyFromMasterKey(key)
|
svcKey := keyservice.KeyFromMasterKey(key)
|
||||||
var part []byte = nil
|
var part []byte
|
||||||
decryptErr := decryptKeyError{
|
decryptErr := decryptKeyError{
|
||||||
keyName: key.ToString(),
|
keyName: key.ToString(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ import (
|
||||||
"go.mozilla.org/sops/stores"
|
"go.mozilla.org/sops/stores"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SopsPrefix is the prefix for all metadatada entry keys
|
||||||
const SopsPrefix = "sops_"
|
const SopsPrefix = "sops_"
|
||||||
|
|
||||||
// Store handles storage of dotenv data
|
// Store handles storage of dotenv data
|
||||||
type Store struct {
|
type Store struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadEncryptedFile loads an encrypted file's bytes onto a sops.Tree runtime object
|
||||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
branches, err := store.LoadPlainFile(in)
|
branches, err := store.LoadPlainFile(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -57,6 +59,8 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPlainFile returns the contents of a plaintext file loaded onto a
|
||||||
|
// sops runtime object
|
||||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
var branches sops.TreeBranches
|
var branches sops.TreeBranches
|
||||||
var branch sops.TreeBranch
|
var branch sops.TreeBranch
|
||||||
|
@ -86,6 +90,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitEncryptedFile returns the encrypted file's bytes corresponding to a sops
|
||||||
|
// runtime object
|
||||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
metadata := stores.MetadataFromInternal(in.Metadata)
|
metadata := stores.MetadataFromInternal(in.Metadata)
|
||||||
mdItems, err := metadataToMap(metadata)
|
mdItems, err := metadataToMap(metadata)
|
||||||
|
@ -101,6 +107,8 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
return store.EmitPlainFile(in.Branches)
|
return store.EmitPlainFile(in.Branches)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitPlainFile returns the plaintext file's bytes corresponding to a sops
|
||||||
|
// runtime object
|
||||||
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
buffer := bytes.Buffer{}
|
buffer := bytes.Buffer{}
|
||||||
for _, item := range in[0] {
|
for _, item := range in[0] {
|
||||||
|
@ -118,6 +126,7 @@ func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
return buffer.Bytes(), nil
|
return buffer.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitValue returns a single value as bytes
|
||||||
func (Store) EmitValue(v interface{}) ([]byte, error) {
|
func (Store) EmitValue(v interface{}) ([]byte, error) {
|
||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
return []byte(s), nil
|
return []byte(s), nil
|
||||||
|
@ -125,6 +134,7 @@ func (Store) EmitValue(v interface{}) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("the dotenv store only supports emitting strings, got %T", v)
|
return nil, fmt.Errorf("the dotenv store only supports emitting strings, got %T", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitExample returns the bytes corresponding to an example Flat Tree runtime object
|
||||||
func (store *Store) EmitExample() []byte {
|
func (store *Store) EmitExample() []byte {
|
||||||
bytes, err := store.EmitPlainFile(stores.ExampleFlatTree.Branches)
|
bytes, err := store.EmitPlainFile(stores.ExampleFlatTree.Branches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -106,7 +106,7 @@ func tokenize(path string) []token {
|
||||||
state = StateList
|
state = StateList
|
||||||
i += len(listSeparator)
|
i += len(listSeparator)
|
||||||
} else {
|
} else {
|
||||||
i += 1
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finishPrevToken()
|
finishPrevToken()
|
||||||
|
|
|
@ -136,6 +136,7 @@ func (store Store) treeItemFromSection(section *ini.Section) (sops.TreeItem, err
|
||||||
return sectionItem, nil
|
return sectionItem, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadEncryptedFile loads encrypted INI file's bytes onto a sops.Tree runtime object
|
||||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
iniFileOuter, err := ini.Load(in)
|
iniFileOuter, err := ini.Load(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -192,6 +193,7 @@ func (store *Store) iniSectionToMetadata(sopsSection *ini.Section) (stores.Metad
|
||||||
return md, err
|
return md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPlainFile loads a plaintext INI file's bytes onto a sops.TreeBranches runtime object
|
||||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
branches, err := store.treeBranchesFromIni(in)
|
branches, err := store.treeBranchesFromIni(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -200,6 +202,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitEncryptedFile returns encrypted INI file bytes corresponding to a sops.Tree
|
||||||
|
// runtime object
|
||||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
|
|
||||||
metadata := stores.MetadataFromInternal(in.Metadata)
|
metadata := stores.MetadataFromInternal(in.Metadata)
|
||||||
|
@ -298,6 +302,7 @@ func encodeMetadataItem(prefix string, kind reflect.Kind, field reflect.Value) (
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitPlainFile returns the plaintext INI file bytes corresponding to a sops.TreeBranches object
|
||||||
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
out, err := store.iniFromTreeBranches(in)
|
out, err := store.iniFromTreeBranches(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -315,10 +320,12 @@ func (store Store) encodeValue(v interface{}) ([]byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitValue returns a single value encoded in a generic interface{} as bytes
|
||||||
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||||
return store.encodeValue(v)
|
return store.encodeValue(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitExample returns the plaintext INI file bytes corresponding to the SimpleTree example
|
||||||
func (store *Store) EmitExample() []byte {
|
func (store *Store) EmitExample() []byte {
|
||||||
bytes, err := store.EmitPlainFile(stores.ExampleSimpleTree.Branches)
|
bytes, err := store.EmitPlainFile(stores.ExampleSimpleTree.Branches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -19,10 +19,13 @@ type BinaryStore struct {
|
||||||
store Store
|
store Store
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadEncryptedFile loads an encrypted json file onto a sops.Tree object
|
||||||
func (store BinaryStore) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
func (store BinaryStore) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
return store.store.LoadEncryptedFile(in)
|
return store.store.LoadEncryptedFile(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPlainFile loads a plaintext json file onto a sops.Tree encapsulated
|
||||||
|
// within a sops.TreeBranches object
|
||||||
func (store BinaryStore) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
func (store BinaryStore) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
return sops.TreeBranches{
|
return sops.TreeBranches{
|
||||||
sops.TreeBranch{
|
sops.TreeBranch{
|
||||||
|
@ -34,10 +37,12 @@ func (store BinaryStore) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitEncryptedFile produces an encrypted json file's bytes from its corresponding sops.Tree object
|
||||||
func (store BinaryStore) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
func (store BinaryStore) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
return store.store.EmitEncryptedFile(in)
|
return store.store.EmitEncryptedFile(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitPlainFile produces plaintext json file's bytes from its corresponding sops.TreeBranches object
|
||||||
func (store BinaryStore) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
func (store BinaryStore) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
// JSON stores a single object per file
|
// JSON stores a single object per file
|
||||||
for _, item := range in[0] {
|
for _, item := range in[0] {
|
||||||
|
@ -48,10 +53,13 @@ func (store BinaryStore) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("No binary data found in tree")
|
return nil, fmt.Errorf("No binary data found in tree")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitValue extracts a value from a generic interface{} object representing a structured set
|
||||||
|
// of binary files
|
||||||
func (store BinaryStore) EmitValue(v interface{}) ([]byte, error) {
|
func (store BinaryStore) EmitValue(v interface{}) ([]byte, error) {
|
||||||
return nil, fmt.Errorf("Binary files are not structured and extracting a single value is not possible")
|
return nil, fmt.Errorf("Binary files are not structured and extracting a single value is not possible")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitExample returns the example's plaintext json file bytes
|
||||||
func (store BinaryStore) EmitExample() []byte {
|
func (store BinaryStore) EmitExample() []byte {
|
||||||
return []byte("Welcome to SOPS! Edit this file as you please!")
|
return []byte("Welcome to SOPS! Edit this file as you please!")
|
||||||
}
|
}
|
||||||
|
@ -207,6 +215,7 @@ func (store Store) reindentJSON(in []byte) ([]byte, error) {
|
||||||
return out.Bytes(), err
|
return out.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadEncryptedFile loads an encrypted secrets file onto a sops.Tree object
|
||||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
// Because we don't know what fields the input file will have, we have to
|
// Because we don't know what fields the input file will have, we have to
|
||||||
// load the file in two steps.
|
// load the file in two steps.
|
||||||
|
@ -252,6 +261,7 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPlainFile loads plaintext json file bytes onto a sops.TreeBranches object
|
||||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
branch, err := store.treeBranchFromJSON(in)
|
branch, err := store.treeBranchFromJSON(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -262,6 +272,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitEncryptedFile returns the encrypted bytes of the json file corresponding to a
|
||||||
|
// sops.Tree runtime object
|
||||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
tree := append(in.Branches[0], sops.TreeItem{Key: "sops", Value: stores.MetadataFromInternal(in.Metadata)})
|
tree := append(in.Branches[0], sops.TreeItem{Key: "sops", Value: stores.MetadataFromInternal(in.Metadata)})
|
||||||
out, err := store.jsonFromTreeBranch(tree)
|
out, err := store.jsonFromTreeBranch(tree)
|
||||||
|
@ -271,6 +283,8 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitPlainFile returns the plaintext bytes of the json file corresponding to a
|
||||||
|
// sops.TreeBranches runtime object
|
||||||
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
out, err := store.jsonFromTreeBranch(in[0])
|
out, err := store.jsonFromTreeBranch(in[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -279,6 +293,8 @@ func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitValue returns bytes corresponding to a single encoded value
|
||||||
|
// in a generic interface{} object
|
||||||
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||||
s, err := store.encodeValue(v)
|
s, err := store.encodeValue(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -287,6 +303,7 @@ func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||||
return store.reindentJSON(s)
|
return store.reindentJSON(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitExample returns the bytes corresponding to an example complex tree
|
||||||
func (store *Store) EmitExample() []byte {
|
func (store *Store) EmitExample() []byte {
|
||||||
bytes, err := store.EmitPlainFile(stores.ExampleComplexTree.Branches)
|
bytes, err := store.EmitPlainFile(stores.ExampleComplexTree.Branches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -309,6 +309,7 @@ func (pgpKey *pgpkey) toInternal() (*pgp.MasterKey, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExampleComplexTree is an example sops.Tree object exhibiting complex relationships
|
||||||
var ExampleComplexTree = sops.Tree{
|
var ExampleComplexTree = sops.Tree{
|
||||||
Branches: sops.TreeBranches{
|
Branches: sops.TreeBranches{
|
||||||
sops.TreeBranch{
|
sops.TreeBranch{
|
||||||
|
@ -343,6 +344,8 @@ var ExampleComplexTree = sops.Tree{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExampleSimpleTree is an example sops.Tree object exhibiting only simple relationships
|
||||||
|
// with only one nested branch and only simple string values
|
||||||
var ExampleSimpleTree = sops.Tree{
|
var ExampleSimpleTree = sops.Tree{
|
||||||
Branches: sops.TreeBranches{
|
Branches: sops.TreeBranches{
|
||||||
sops.TreeBranch{
|
sops.TreeBranch{
|
||||||
|
@ -367,6 +370,8 @@ var ExampleSimpleTree = sops.Tree{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExampleFlatTree is an example sops.Tree object exhibiting only simple relationships
|
||||||
|
// with no nested branches and only simple string values
|
||||||
var ExampleFlatTree = sops.Tree{
|
var ExampleFlatTree = sops.Tree{
|
||||||
Branches: sops.TreeBranches{
|
Branches: sops.TreeBranches{
|
||||||
sops.TreeBranch{
|
sops.TreeBranch{
|
||||||
|
|
|
@ -101,6 +101,8 @@ func (store Store) treeBranchToYamlMap(in sops.TreeBranch) yaml.MapSlice {
|
||||||
return branch
|
return branch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadEncryptedFile loads the contents of an encrypted yaml file onto a
|
||||||
|
// sops.Tree runtime object
|
||||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
var data []yaml.MapSlice
|
var data []yaml.MapSlice
|
||||||
if err := (yaml.CommentUnmarshaler{}).UnmarshalDocuments(in, &data); err != nil {
|
if err := (yaml.CommentUnmarshaler{}).UnmarshalDocuments(in, &data); err != nil {
|
||||||
|
@ -136,6 +138,8 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadPlainFile loads the contents of a plaintext yaml file onto a
|
||||||
|
// sops.Tree runtime obejct
|
||||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
var data []yaml.MapSlice
|
var data []yaml.MapSlice
|
||||||
if err := (yaml.CommentUnmarshaler{}).UnmarshalDocuments(in, &data); err != nil {
|
if err := (yaml.CommentUnmarshaler{}).UnmarshalDocuments(in, &data); err != nil {
|
||||||
|
@ -149,6 +153,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||||
return branches, nil
|
return branches, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitEncryptedFile returns the encrypted bytes of the yaml file corresponding to a
|
||||||
|
// sops.Tree runtime object
|
||||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
out := []byte{}
|
out := []byte{}
|
||||||
for i, branch := range in.Branches {
|
for i, branch := range in.Branches {
|
||||||
|
@ -166,6 +172,8 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitPlainFile returns the plaintext bytes of the yaml file corresponding to a
|
||||||
|
// sops.TreeBranches runtime object
|
||||||
func (store *Store) EmitPlainFile(branches sops.TreeBranches) ([]byte, error) {
|
func (store *Store) EmitPlainFile(branches sops.TreeBranches) ([]byte, error) {
|
||||||
var out []byte
|
var out []byte
|
||||||
for i, branch := range branches {
|
for i, branch := range branches {
|
||||||
|
@ -182,11 +190,14 @@ func (store *Store) EmitPlainFile(branches sops.TreeBranches) ([]byte, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitValue returns bytes corresponding to a single encoded value
|
||||||
|
// in a generic interface{} object
|
||||||
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||||
v = store.treeValueToYamlValue(v)
|
v = store.treeValueToYamlValue(v)
|
||||||
return (&yaml.YAMLMarshaler{Indent: 4}).Marshal(v)
|
return (&yaml.YAMLMarshaler{Indent: 4}).Marshal(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmitExample returns the bytes corresponding to an example complex tree
|
||||||
func (store *Store) EmitExample() []byte {
|
func (store *Store) EmitExample() []byte {
|
||||||
bytes, err := store.EmitPlainFile(stores.ExampleComplexTree.Branches)
|
bytes, err := store.EmitPlainFile(stores.ExampleComplexTree.Branches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,8 +10,10 @@ import (
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Version represents the value of the current semantic version
|
||||||
const Version = "3.3.1"
|
const Version = "3.3.1"
|
||||||
|
|
||||||
|
// PrintVersion handles the version command for sops
|
||||||
func PrintVersion(c *cli.Context) {
|
func PrintVersion(c *cli.Context) {
|
||||||
out := fmt.Sprintf("%s %s", c.App.Name, c.App.Version)
|
out := fmt.Sprintf("%s %s", c.App.Name, c.App.Version)
|
||||||
upstreamVersion, err := RetrieveLatestVersionFromUpstream()
|
upstreamVersion, err := RetrieveLatestVersionFromUpstream()
|
||||||
|
|
Загрузка…
Ссылка в новой задаче