예제 #1
0
파일: common.go 프로젝트: jgrocho/pass
func decrypt(ringPath string, input io.Reader) (io.Reader, error) {
	ringFile, err := os.Open(ringPath)
	if err != nil {
		return nil, err
	}
	defer ringFile.Close()

	ring, err := openpgp.ReadKeyRing(ringFile)
	if err != nil {
		return nil, err
	}

	var keyToTry, attempt int
	var triedCache bool
	promptFunc := openpgp.PromptFunction(func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
		if keyToTry >= len(keys) {
			return nil, fmt.Errorf("no more keys to try")
		}
		if attempt > 2 {
			attempt = 0
			keyToTry++
			return nil, nil
		}
		defer func() { attempt++ }()

		key := keys[keyToTry]
		fingerprint := fmt.Sprintf("%X", key.PublicKey.Fingerprint)

		if !triedCache {
			triedCache = true
			if cachedPass, _ := passphrase.GetPassphrase(fingerprint, "", "", "", false, false); cachedPass != "" {
				if err := key.PrivateKey.Decrypt([]byte(cachedPass)); err == nil {
					return nil, nil
				}
			}
		}

		passphrase.ClearCachedPassphrase(fingerprint)
		prompt := ""
		description := fmt.Sprintf("Key %s; attempt %d", key.PublicKey.KeyIdShortString(), attempt+1)
		passwd, err := passphrase.GetPassphrase(fingerprint, prompt, description, "", true, false)
		if err != nil {
			return nil, err
		}
		key.PrivateKey.Decrypt([]byte(passwd))

		return nil, nil
	})

	msgDetails, err := openpgp.ReadMessage(input, ring, promptFunc, nil)
	if err != nil {
		return nil, err
	}

	return msgDetails.UnverifiedBody, nil
}
예제 #2
0
파일: add.go 프로젝트: jgrocho/pass
func (cmd *add) Run(globals options.Options, args []string) error {
	prefix := string(globals.Prefix)
	name, passfile, err := getNameAndFile(prefix, args)
	if err != nil {
		return err
	}

	if _, err := os.Stat(passfile); err == nil && !cmd.force {
		return &CmdError{4, "an entry already exists for " + name + ". Use -force to overwrite it"}
	}

	passdir := filepath.Dir(passfile)
	if _, err := os.Stat(passdir); err != nil && os.IsNotExist(err) {
		if err := os.MkdirAll(passdir, 0777); err != nil {
			return ErrNotAdding(name, "could not create directory "+passdir)
		}
	}

	outfile, err := os.Create(passfile)
	if err != nil {
		return ErrNotAdding(name, "could not open file")
	}
	defer outfile.Close()

	var input io.Reader = os.Stdin
	if cmd.edit != "" {
		tempfile, err := ioutil.TempFile("", "pass_"+name)
		defer os.Remove(tempfile.Name())
		if err != nil {
			return ErrNotAdding(name, "could not create temporary file for editing")
		}
		editor := exec.Command(cmd.edit, tempfile.Name())
		editor.Stdin = os.Stdin
		editor.Stdout = os.Stdout
		editor.Stderr = os.Stderr
		if err := editor.Run(); err != nil {
			return ErrNotAdding(name, "failed running editor: "+cmd.edit)
		}
		input = tempfile
	} else if isTerminal(os.Stdin) {
		passwd, err := passphrase.GetPassphrase("", "", "Please enter a password for "+name, "", true, true)
		if err != nil {
			return ErrNotAdding(name, "could not get a passphrase")
		}
		input = strings.NewReader(passwd + "\n")
	}

	if err := encrypt(string(globals.PubRing), input, outfile); err != nil {
		return ErrNotAdding(name, "could not encrypt passphrase")
	}

	relative := passfile[len(prefix)+1:]
	if err := addAndCommit(prefix, relative, "Add password for "+name); err != nil {
		return &CmdError{4, "failed to commit passphrase to repository"}
	}

	return nil
}