github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/pwlib/get_password.go (about)

     1  package pwlib
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/tommi2day/gomodules/common"
    10  
    11  	log "github.com/sirupsen/logrus"
    12  )
    13  
    14  // Methods all available methods for get_passwword
    15  var Methods = []string{typeGO, typeOpenssl, typeEnc, typePlain, typeVault, typeGPG, typeGopass, typeKMS}
    16  
    17  // DecryptFile decripts an rsa protected file
    18  func (pc *PassConfig) DecryptFile() (lines []string, err error) {
    19  	cryptedfile := pc.CryptedFile
    20  	privatekeyfile := pc.PrivateKeyFile
    21  	keypass := pc.KeyPass
    22  	datadir := pc.DataDir
    23  	sessionpassfile := pc.SessionPassFile
    24  	passflag := "open"
    25  	content := ""
    26  	method := pc.Method
    27  	keyID := pc.KMSKeyID
    28  	var data []byte
    29  	if len(keypass) > 0 {
    30  		passflag = "Encypted"
    31  	}
    32  	log.Debugf("Decrypt data from %s with method %s(%s)", cryptedfile, method, passflag)
    33  
    34  	switch method {
    35  	case typeOpenssl:
    36  		content, err = PrivateDecryptFileSSL(cryptedfile, privatekeyfile, keypass, sessionpassfile)
    37  	case typeGO:
    38  		content, err = PrivateDecryptFileGo(cryptedfile, privatekeyfile, keypass)
    39  	case typeEnc:
    40  		data, err = DecodeFile(cryptedfile)
    41  		content = string(data)
    42  	case typePlain:
    43  		//nolint gosec
    44  		data, err = os.ReadFile(cryptedfile)
    45  		content = string(data)
    46  	case typeVault:
    47  		content, err = GetVaultSecret(cryptedfile, "", "")
    48  	case typeGPG:
    49  		content, err = GPGDecryptFile(cryptedfile, privatekeyfile, keypass, "")
    50  	case typeGopass:
    51  		content, err = GetGopassSecrets(datadir, privatekeyfile, keypass)
    52  	case typeKMS:
    53  		content, err = KMSDecryptFile(cryptedfile, keyID, sessionpassfile)
    54  	default:
    55  		log.Fatalf("encryption method %s not known", method)
    56  		os.Exit(1)
    57  	}
    58  
    59  	if err != nil {
    60  		log.Debug("load data failed")
    61  		return
    62  	}
    63  	content = strings.ReplaceAll(content, "\r", "")
    64  	lines = strings.Split(content, "\n")
    65  	log.Debug("load data success")
    66  	return
    67  }
    68  
    69  // EncryptFile encrypt plain text to rsa protected file
    70  func (pc *PassConfig) EncryptFile() (err error) {
    71  	cryptedFile := pc.CryptedFile
    72  	pubKeyFile := pc.PubKeyFile
    73  	plaintextfile := pc.PlainTextFile
    74  	sessionpassfile := pc.SessionPassFile
    75  	method := pc.Method
    76  	keyID := pc.KMSKeyID
    77  	log.Debugf("Encrypt data from %s method %s", plaintextfile, method)
    78  	switch method {
    79  	case typeOpenssl:
    80  		err = PubEncryptFileSSL(plaintextfile, cryptedFile, pubKeyFile, sessionpassfile)
    81  	case typeGO:
    82  		err = PubEncryptFileGo(plaintextfile, cryptedFile, pubKeyFile)
    83  	case typeEnc:
    84  		err = EncodeFile(plaintextfile, cryptedFile)
    85  	case typePlain:
    86  		// no need to do anything
    87  		err = nil
    88  	case typeGPG:
    89  		err = GPGEncryptFile(plaintextfile, cryptedFile, pubKeyFile)
    90  	case typeKMS:
    91  		err = KMSEncryptFile(plaintextfile, cryptedFile, keyID, sessionpassfile)
    92  	case typeVault, typeGopass:
    93  		// not implemented yet
    94  		err = fmt.Errorf("encryption method %s not implemented yet", method)
    95  	default:
    96  		log.Fatalf("Enc method %s not known", method)
    97  		os.Exit(1)
    98  	}
    99  
   100  	if err != nil {
   101  		log.Debug("encryption data failed")
   102  		return
   103  	}
   104  	log.Debug("encryption data success")
   105  	return
   106  }
   107  
   108  // ListPasswords printout list of pwcli
   109  func (pc *PassConfig) ListPasswords() (lines []string, err error) {
   110  	log.Debugf("ListPasswords entered")
   111  	lines, err = pc.DecryptFile()
   112  	if err != nil {
   113  		log.Errorf("Decode Failed")
   114  		return
   115  	}
   116  	return
   117  }
   118  
   119  // GetPassword ask System for data
   120  func (pc *PassConfig) GetPassword(system string, account string) (password string, err error) {
   121  	var lines []string
   122  	log.Debugf("GetPassword for '%s'@'%s' entered", account, system)
   123  	if pc.Method == typeVault {
   124  		// in vault mode we use cryptedfile to handover vault path
   125  		pc.CryptedFile = system
   126  	}
   127  	lines, err = pc.DecryptFile()
   128  	if err != nil {
   129  		return
   130  	}
   131  	found := false
   132  	direct := false
   133  	if pc.Method == typeVault {
   134  		// in vault mode we need to replace ":" in system = vault path to match
   135  		system = strings.ReplaceAll(system, ":", "_")
   136  	}
   137  
   138  	// match strings in function to make linter happy
   139  	password, found, direct = pc.match(lines, system, account)
   140  	// not found
   141  	if !found {
   142  		msg := fmt.Sprintf("no record found for '%s'@'%s'", account, system)
   143  		log.Debug("GetPassword finished with no Match")
   144  		err = errors.New(msg)
   145  		return
   146  	}
   147  
   148  	// found
   149  	if !direct {
   150  		log.Debug("use default entry")
   151  	}
   152  	return
   153  }
   154  
   155  func (pc *PassConfig) match(lines []string, system string, account string) (password string, found bool, direct bool) {
   156  	password = ""
   157  	found = false
   158  	direct = false
   159  	for _, line := range lines {
   160  		if common.CheckSkip(line) {
   161  			continue
   162  		}
   163  		fields := strings.SplitN(line, ":", 3)
   164  		if len(fields) != 3 {
   165  			log.Debugf("Skip incomplete record %s", line)
   166  			continue
   167  		}
   168  		if system == fields[0] && account == fields[1] {
   169  			log.Debug("Found direct match")
   170  			if found {
   171  				log.Debug("Overwrite previous default candidate")
   172  			}
   173  			found = true
   174  			direct = true
   175  			password = fields[2]
   176  			break
   177  		}
   178  		if pc.Method == typeVault || pc.Method == typeGopass {
   179  			// vault method has no default entries
   180  			continue
   181  		}
   182  		if fields[0] == "!default" && account == fields[1] {
   183  			password = fields[2]
   184  			log.Debug("found new default match candidate")
   185  			if found {
   186  				log.Debug("Overwrite previous default candidate")
   187  			}
   188  			found = true
   189  		}
   190  	}
   191  	return
   192  }