Implement fetch
action, normalize error response params (#13)
This commit is contained in:
27
PROTOCOL.md
27
PROTOCOL.md
@@ -42,17 +42,22 @@ should be supplied as a `message` parameter.
|
|||||||
## List of Error Codes
|
## List of Error Codes
|
||||||
|
|
||||||
| Code | Description | Parameters |
|
| Code | Description | Parameters |
|
||||||
| ---- | ----------------------------------------------------------------------- | ----------------------- |
|
| ---- | ----------------------------------------------------------------------- | -------------------------------------------------- |
|
||||||
| 10 | Unable to parse browser request length | error |
|
| 10 | Unable to parse browser request length | message, error |
|
||||||
| 11 | Unable to parse browser request | error |
|
| 11 | Unable to parse browser request | message, error |
|
||||||
| 12 | Invalid request action | action |
|
| 12 | Invalid request action | message, action |
|
||||||
| 13 | Inaccessible user-configured password store | error, name, path |
|
| 13 | Inaccessible user-configured password store | message, action, error, storePath, storeName |
|
||||||
| 14 | Inaccessible default password store | error, path |
|
| 14 | Inaccessible default password store | message, action, error, storePath |
|
||||||
| 15 | Unable to determine the location of the default password store | error |
|
| 15 | Unable to determine the location of the default password store | message, action, error |
|
||||||
| 16 | Unable to read the default settings of a user-configured password store | error, name, path |
|
| 16 | Unable to read the default settings of a user-configured password store | message, action, error, storePath, storeName |
|
||||||
| 17 | Unable to read the default settings of the default password store | error, path |
|
| 17 | Unable to read the default settings of the default password store | message, action, error, storePath |
|
||||||
| 18 | Unable to list files in a password store | error, name, path |
|
| 18 | Unable to list files in a password store | message, action, error, storePath, storeName |
|
||||||
| 19 | Unable to determine a relative path for a file in a password store | error, file, name, path |
|
| 19 | Unable to determine a relative path for a file in a password store | message, action, error, storePath, storeName, file |
|
||||||
|
| 20 | Invalid password store name | message, action, storeName |
|
||||||
|
| 21 | Invalid gpg path | message, action, error, gpgPath |
|
||||||
|
| 22 | Unable to detect the location of the gpg binary | message, action, error |
|
||||||
|
| 23 | Invalid password file extension | message, action, file |
|
||||||
|
| 24 | Unable to decrypt the password file | message, action, error, storePath, storeName, file |
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
|
@@ -17,28 +17,69 @@ const (
|
|||||||
CodeParseRequest Code = 11
|
CodeParseRequest Code = 11
|
||||||
|
|
||||||
// CodeInvalidRequestAction error parsing a request action
|
// CodeInvalidRequestAction error parsing a request action
|
||||||
CodeInvalidRequestAction = 12
|
CodeInvalidRequestAction Code = 12
|
||||||
|
|
||||||
// CodeInaccessiblePasswordStore error accessing a user-configured password store
|
// CodeInaccessiblePasswordStore error accessing a user-configured password store
|
||||||
CodeInaccessiblePasswordStore = 13
|
CodeInaccessiblePasswordStore Code = 13
|
||||||
|
|
||||||
// CodeInaccessibleDefaultPasswordStore error accessing the default password store
|
// CodeInaccessibleDefaultPasswordStore error accessing the default password store
|
||||||
CodeInaccessibleDefaultPasswordStore = 14
|
CodeInaccessibleDefaultPasswordStore Code = 14
|
||||||
|
|
||||||
// CodeUnknownDefaultPasswordStoreLocation error determining the location of the default password store
|
// CodeUnknownDefaultPasswordStoreLocation error determining the location of the default password store
|
||||||
CodeUnknownDefaultPasswordStoreLocation = 15
|
CodeUnknownDefaultPasswordStoreLocation Code = 15
|
||||||
|
|
||||||
// CodeUnreadablePasswordStoreDefaultSettings error reading the default settings of a user-configured password store
|
// CodeUnreadablePasswordStoreDefaultSettings error reading the default settings of a user-configured password store
|
||||||
CodeUnreadablePasswordStoreDefaultSettings = 16
|
CodeUnreadablePasswordStoreDefaultSettings Code = 16
|
||||||
|
|
||||||
// CodeUnreadableDefaultPasswordStoreDefaultSettings error reading the default settings of the default password store
|
// CodeUnreadableDefaultPasswordStoreDefaultSettings error reading the default settings of the default password store
|
||||||
CodeUnreadableDefaultPasswordStoreDefaultSettings = 17
|
CodeUnreadableDefaultPasswordStoreDefaultSettings Code = 17
|
||||||
|
|
||||||
// CodeUnableToListFilesInPasswordStore error listing files in a password store
|
// CodeUnableToListFilesInPasswordStore error listing files in a password store
|
||||||
CodeUnableToListFilesInPasswordStore = 18
|
CodeUnableToListFilesInPasswordStore Code = 18
|
||||||
|
|
||||||
// CodeUnableToDetermineRelativeFilePathInPasswordStore error determining a relative path for a file in a password store
|
// CodeUnableToDetermineRelativeFilePathInPasswordStore error determining a relative path for a file in a password store
|
||||||
CodeUnableToDetermineRelativeFilePathInPasswordStore = 19
|
CodeUnableToDetermineRelativeFilePathInPasswordStore Code = 19
|
||||||
|
|
||||||
|
// CodeInvalidPasswordStore error looking for a password store with the given name
|
||||||
|
CodeInvalidPasswordStore Code = 20
|
||||||
|
|
||||||
|
// CodeInvalidGpgPath error looking for a gpg binary at the given path
|
||||||
|
CodeInvalidGpgPath Code = 21
|
||||||
|
|
||||||
|
// CodeUnableToDetectGpgPath error detecting the location of the gpg binary
|
||||||
|
CodeUnableToDetectGpgPath Code = 22
|
||||||
|
|
||||||
|
// CodeInvalidPasswordFileExtension error unexpected password file extension
|
||||||
|
CodeInvalidPasswordFileExtension Code = 23
|
||||||
|
|
||||||
|
// CodeUnableToDecryptPasswordFile error decrypting a password file
|
||||||
|
CodeUnableToDecryptPasswordFile Code = 24
|
||||||
|
)
|
||||||
|
|
||||||
|
// Field extra field in the error response params
|
||||||
|
type Field string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// FieldMessage a user-friendly error message, always present
|
||||||
|
FieldMessage Field = "message"
|
||||||
|
|
||||||
|
// FieldAction a browser request action that resulted in a failure
|
||||||
|
FieldAction Field = "action"
|
||||||
|
|
||||||
|
// FieldError an error message returned from an external system
|
||||||
|
FieldError Field = "error"
|
||||||
|
|
||||||
|
// FieldStoreName a password store name
|
||||||
|
FieldStoreName Field = "storeName"
|
||||||
|
|
||||||
|
// FieldStorePath a password store path
|
||||||
|
FieldStorePath Field = "storePath"
|
||||||
|
|
||||||
|
// FieldFile a password file
|
||||||
|
FieldFile Field = "file"
|
||||||
|
|
||||||
|
// FieldGpgPath a path to the gpg binary
|
||||||
|
FieldGpgPath Field = "gpgPath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExitWithCode exit with error code
|
// ExitWithCode exit with error code
|
||||||
|
@@ -23,12 +23,16 @@ func configure(request request) {
|
|||||||
"The password store '%v' is not accessible at the location '%v': %+v",
|
"The password store '%v' is not accessible at the location '%v': %+v",
|
||||||
store.Name, store.Path, err,
|
store.Name, store.Path, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeInaccessiblePasswordStore,
|
errors.CodeInaccessiblePasswordStore,
|
||||||
"The password store is not accessible",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "name": store.Name, "path": store.Path},
|
errors.FieldMessage: "The password store is not accessible",
|
||||||
|
errors.FieldAction: "configure",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeInaccessiblePasswordStore)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
store.Path = normalizedStorePath
|
store.Path = normalizedStorePath
|
||||||
@@ -39,12 +43,16 @@ func configure(request request) {
|
|||||||
"Unable to read the default settings of the user-configured password store '%v' in '%v': %+v",
|
"Unable to read the default settings of the user-configured password store '%v' in '%v': %+v",
|
||||||
store.Name, store.Path, err,
|
store.Name, store.Path, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeUnreadablePasswordStoreDefaultSettings,
|
errors.CodeUnreadablePasswordStoreDefaultSettings,
|
||||||
"Unable to read the default settings of the password store",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "name": store.Name, "path": store.Path},
|
errors.FieldMessage: "Unable to read the default settings of the password store",
|
||||||
|
errors.FieldAction: "configure",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeUnreadablePasswordStoreDefaultSettings)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,12 +63,14 @@ func configure(request request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if len(request.Settings.Stores) == 0 {
|
if len(request.Settings.Stores) == 0 {
|
||||||
log.Error("Unable to determine the location of the default password store: ", err)
|
log.Error("Unable to determine the location of the default password store: ", err)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeUnknownDefaultPasswordStoreLocation,
|
errors.CodeUnknownDefaultPasswordStoreLocation,
|
||||||
"Unable to determine the location of the default password store",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error()},
|
errors.FieldMessage: "Unable to determine the location of the default password store",
|
||||||
|
errors.FieldAction: "configure",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeUnknownDefaultPasswordStoreLocation)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
responseData.DefaultStore.Path, err = normalizePasswordStorePath(possibleDefaultStorePath)
|
responseData.DefaultStore.Path, err = normalizePasswordStorePath(possibleDefaultStorePath)
|
||||||
@@ -70,12 +80,15 @@ func configure(request request) {
|
|||||||
"The default password store is not accessible at the location '%v': %+v",
|
"The default password store is not accessible at the location '%v': %+v",
|
||||||
possibleDefaultStorePath, err,
|
possibleDefaultStorePath, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeInaccessibleDefaultPasswordStore,
|
errors.CodeInaccessibleDefaultPasswordStore,
|
||||||
"The default password store is not accessible",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "path": possibleDefaultStorePath},
|
errors.FieldMessage: "The default password store is not accessible",
|
||||||
|
errors.FieldAction: "configure",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStorePath: possibleDefaultStorePath,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeInaccessibleDefaultPasswordStore)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,12 +100,15 @@ func configure(request request) {
|
|||||||
"Unable to read the default settings of the default password store in '%v': %+v",
|
"Unable to read the default settings of the default password store in '%v': %+v",
|
||||||
responseData.DefaultStore.Path, err,
|
responseData.DefaultStore.Path, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeUnreadableDefaultPasswordStoreDefaultSettings,
|
errors.CodeUnreadableDefaultPasswordStoreDefaultSettings,
|
||||||
"Unable to read the default settings of the default password store",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "path": responseData.DefaultStore.Path},
|
errors.FieldMessage: "Unable to read the default settings of the default password store",
|
||||||
|
errors.FieldAction: "configure",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStorePath: responseData.DefaultStore.Path,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeUnreadableDefaultPasswordStoreDefaultSettings)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
164
request/fetch.go
Normal file
164
request/fetch.go
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
goerrors "errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/browserpass/browserpass-native/errors"
|
||||||
|
"github.com/browserpass/browserpass-native/response"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fetchDecryptedContents(request request) {
|
||||||
|
responseData := response.MakeFetchResponse()
|
||||||
|
|
||||||
|
if !strings.HasSuffix(request.File, ".gpg") {
|
||||||
|
log.Errorf("The requested password file '%v' does not have the expected '.gpg' extension", request.File)
|
||||||
|
response.SendErrorAndExit(
|
||||||
|
errors.CodeInvalidPasswordFileExtension,
|
||||||
|
&map[errors.Field]string{
|
||||||
|
errors.FieldMessage: "The requested password file does not have the expected '.gpg' extension",
|
||||||
|
errors.FieldAction: "fetch",
|
||||||
|
errors.FieldFile: request.File,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
store, ok := request.Settings.Stores[request.Store]
|
||||||
|
if !ok {
|
||||||
|
log.Errorf(
|
||||||
|
"The password store '%v' is not present in the list of stores '%v'",
|
||||||
|
request.Store, request.Settings.Stores,
|
||||||
|
)
|
||||||
|
response.SendErrorAndExit(
|
||||||
|
errors.CodeInvalidPasswordStore,
|
||||||
|
&map[errors.Field]string{
|
||||||
|
errors.FieldMessage: "The password store is not present in the list of stores",
|
||||||
|
errors.FieldAction: "fetch",
|
||||||
|
errors.FieldStoreName: request.Store,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizedStorePath, err := normalizePasswordStorePath(store.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(
|
||||||
|
"The password store '%v' is not accessible at the location '%v': %+v",
|
||||||
|
store.Name, store.Path, err,
|
||||||
|
)
|
||||||
|
response.SendErrorAndExit(
|
||||||
|
errors.CodeInaccessiblePasswordStore,
|
||||||
|
&map[errors.Field]string{
|
||||||
|
errors.FieldMessage: "The password store is not accessible",
|
||||||
|
errors.FieldAction: "fetch",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
store.Path = normalizedStorePath
|
||||||
|
|
||||||
|
gpgPath := request.Settings.GpgPath
|
||||||
|
if gpgPath != "" {
|
||||||
|
err = validateGpgBinary(gpgPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(
|
||||||
|
"The provided gpg binary path '%v' is invalid: %+v",
|
||||||
|
gpgPath, err,
|
||||||
|
)
|
||||||
|
response.SendErrorAndExit(
|
||||||
|
errors.CodeInvalidGpgPath,
|
||||||
|
&map[errors.Field]string{
|
||||||
|
errors.FieldMessage: "The provided gpg binary path is invalid",
|
||||||
|
errors.FieldAction: "fetch",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldGpgPath: gpgPath,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gpgPath, err = detectGpgBinary()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to detect the location of the gpg binary: ", err)
|
||||||
|
response.SendErrorAndExit(
|
||||||
|
errors.CodeUnableToDetectGpgPath,
|
||||||
|
&map[errors.Field]string{
|
||||||
|
errors.FieldMessage: "Unable to detect the location of the gpg binary",
|
||||||
|
errors.FieldAction: "fetch",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData.Contents, err = decryptFile(store, request.File, gpgPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(
|
||||||
|
"Unable to decrypt the password file '%v' in the password store '%v' located in '%v': %+v",
|
||||||
|
request.File, store.Name, store.Path, err,
|
||||||
|
)
|
||||||
|
response.SendErrorAndExit(
|
||||||
|
errors.CodeUnableToDecryptPasswordFile,
|
||||||
|
&map[errors.Field]string{
|
||||||
|
errors.FieldMessage: "Unable to decrypt the password file",
|
||||||
|
errors.FieldAction: "fetch",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldFile: request.File,
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
response.SendOk(responseData)
|
||||||
|
}
|
||||||
|
|
||||||
|
func detectGpgBinary() (string, error) {
|
||||||
|
// Look in $PATH first, then check common locations - the first successful result wins
|
||||||
|
gpgBinaryPriorityList := []string{
|
||||||
|
"gpg2", "gpg",
|
||||||
|
"/bin/gpg2", "/usr/bin/gpg2", "/usr/local/bin/gpg2",
|
||||||
|
"/bin/gpg", "/usr/bin/gpg", "/usr/local/bin/gpg",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, binary := range gpgBinaryPriorityList {
|
||||||
|
err := validateGpgBinary(binary)
|
||||||
|
if err == nil {
|
||||||
|
return binary, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", goerrors.New("Unable to detect the location of the gpg binary to use")
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateGpgBinary(gpgPath string) error {
|
||||||
|
return exec.Command(gpgPath, "--version").Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptFile(store store, file string, gpgPath string) (string, error) {
|
||||||
|
passwordFilePath := filepath.Join(store.Path, file)
|
||||||
|
passwordFile, err := os.Open(passwordFilePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
gpgOptions := []string{"--decrypt", "--yes", "--quiet", "--batch", "-"}
|
||||||
|
|
||||||
|
cmd := exec.Command(gpgPath, gpgOptions...)
|
||||||
|
cmd.Stdin = passwordFile
|
||||||
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return "", goerrors.New(fmt.Sprintf("Error: %s, Stderr: %s", err.Error(), stderr.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdout.String(), nil
|
||||||
|
}
|
@@ -20,12 +20,16 @@ func listFiles(request request) {
|
|||||||
"The password store '%v' is not accessible at the location '%v': %+v",
|
"The password store '%v' is not accessible at the location '%v': %+v",
|
||||||
store.Name, store.Path, err,
|
store.Name, store.Path, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeInaccessiblePasswordStore,
|
errors.CodeInaccessiblePasswordStore,
|
||||||
"The password store is not accessible",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "name": store.Name, "path": store.Path},
|
errors.FieldMessage: "The password store is not accessible",
|
||||||
|
errors.FieldAction: "list",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeInaccessiblePasswordStore)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
store.Path = normalizedStorePath
|
store.Path = normalizedStorePath
|
||||||
@@ -36,12 +40,16 @@ func listFiles(request request) {
|
|||||||
"Unable to list the files in the password store '%v' at the location '%v': %+v",
|
"Unable to list the files in the password store '%v' at the location '%v': %+v",
|
||||||
store.Name, store.Path, err,
|
store.Name, store.Path, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeUnableToListFilesInPasswordStore,
|
errors.CodeUnableToListFilesInPasswordStore,
|
||||||
"Unable to list the files in the password store",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "name": store.Name, "path": store.Path},
|
errors.FieldMessage: "Unable to list the files in the password store",
|
||||||
|
errors.FieldAction: "list",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeUnableToListFilesInPasswordStore)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, file := range files {
|
for i, file := range files {
|
||||||
@@ -51,12 +59,17 @@ func listFiles(request request) {
|
|||||||
"Unable to determine the relative path for a file '%v' in the password store '%v' at the location '%v': %+v",
|
"Unable to determine the relative path for a file '%v' in the password store '%v' at the location '%v': %+v",
|
||||||
file, store.Name, store.Path, err,
|
file, store.Name, store.Path, err,
|
||||||
)
|
)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeUnableToDetermineRelativeFilePathInPasswordStore,
|
errors.CodeUnableToDetermineRelativeFilePathInPasswordStore,
|
||||||
"Unable to determine the relative path for a file in the password store",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error(), "file": file, "name": store.Name, "path": store.Path},
|
errors.FieldMessage: "Unable to determine the relative path for a file in the password store",
|
||||||
|
errors.FieldAction: "list",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
errors.FieldFile: file,
|
||||||
|
errors.FieldStoreName: store.Name,
|
||||||
|
errors.FieldStorePath: store.Path,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeUnableToDetermineRelativeFilePathInPasswordStore)
|
|
||||||
}
|
}
|
||||||
files[i] = relativePath
|
files[i] = relativePath
|
||||||
}
|
}
|
||||||
|
@@ -11,15 +11,21 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type request struct {
|
type store struct {
|
||||||
Action string `json:"action"`
|
|
||||||
Settings struct {
|
|
||||||
GpgPath string `json:"gpgPath"`
|
|
||||||
Stores map[string]struct {
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
} `json:"settings"`
|
|
||||||
|
type settings struct {
|
||||||
|
GpgPath string `json:"gpgPath"`
|
||||||
|
Stores map[string]store `json:"stores"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type request struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Settings settings `json:"settings"`
|
||||||
|
File string `json:"file"`
|
||||||
|
Store string `json:"store"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process handles browser request
|
// Process handles browser request
|
||||||
@@ -33,15 +39,16 @@ func Process() {
|
|||||||
case "list":
|
case "list":
|
||||||
listFiles(request)
|
listFiles(request)
|
||||||
case "fetch":
|
case "fetch":
|
||||||
break
|
fetchDecryptedContents(request)
|
||||||
default:
|
default:
|
||||||
log.Errorf("Received a browser request with an unknown action: %+v", request)
|
log.Errorf("Received a browser request with an unknown action: %+v", request)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeInvalidRequestAction,
|
errors.CodeInvalidRequestAction,
|
||||||
"Invalid request action",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"action": request.Action},
|
errors.FieldMessage: "Invalid request action",
|
||||||
|
errors.FieldAction: request.Action,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeInvalidRequestAction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,17 +56,14 @@ func Process() {
|
|||||||
func parseRequestLength() uint32 {
|
func parseRequestLength() uint32 {
|
||||||
var length uint32
|
var length uint32
|
||||||
if err := binary.Read(os.Stdin, binary.LittleEndian, &length); err != nil {
|
if err := binary.Read(os.Stdin, binary.LittleEndian, &length); err != nil {
|
||||||
// TODO: Original browserpass ignores EOF as if it is expected, is it true?
|
|
||||||
// if err == io.EOF {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
log.Error("Unable to parse the length of the browser request: ", err)
|
log.Error("Unable to parse the length of the browser request: ", err)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeParseRequestLength,
|
errors.CodeParseRequestLength,
|
||||||
"Unable to parse the length of the browser request",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error()},
|
errors.FieldMessage: "Unable to parse the length of the browser request",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeParseRequestLength)
|
|
||||||
}
|
}
|
||||||
return length
|
return length
|
||||||
}
|
}
|
||||||
@@ -70,12 +74,13 @@ func parseRequest(messageLength uint32) request {
|
|||||||
reader := &io.LimitedReader{R: os.Stdin, N: int64(messageLength)}
|
reader := &io.LimitedReader{R: os.Stdin, N: int64(messageLength)}
|
||||||
if err := json.NewDecoder(reader).Decode(&parsed); err != nil {
|
if err := json.NewDecoder(reader).Decode(&parsed); err != nil {
|
||||||
log.Error("Unable to parse the browser request: ", err)
|
log.Error("Unable to parse the browser request: ", err)
|
||||||
response.SendError(
|
response.SendErrorAndExit(
|
||||||
errors.CodeParseRequest,
|
errors.CodeParseRequest,
|
||||||
"Unable to parse the browser request",
|
&map[errors.Field]string{
|
||||||
&map[string]string{"error": err.Error()},
|
errors.FieldMessage: "Unable to parse the browser request",
|
||||||
|
errors.FieldError: err.Error(),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
errors.ExitWithCode(errors.CodeParseRequest)
|
|
||||||
}
|
}
|
||||||
return parsed
|
return parsed
|
||||||
}
|
}
|
||||||
|
@@ -52,6 +52,16 @@ func MakeListResponse() *ListResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchResponse a response format for the "fetch" request
|
||||||
|
type FetchResponse struct {
|
||||||
|
Contents string `json:"contents"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeFetchResponse initializes an empty fetch response
|
||||||
|
func MakeFetchResponse() *FetchResponse {
|
||||||
|
return &FetchResponse{}
|
||||||
|
}
|
||||||
|
|
||||||
// SendOk sends a success response to the browser extension in the predefined json format
|
// SendOk sends a success response to the browser extension in the predefined json format
|
||||||
func SendOk(data interface{}) {
|
func SendOk(data interface{}) {
|
||||||
send(&okResponse{
|
send(&okResponse{
|
||||||
@@ -61,22 +71,16 @@ func SendOk(data interface{}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendError sends an error response to the browser extension in the predefined json format
|
// SendErrorAndExit sends an error response to the browser extension in the predefined json format and exits with the specified exit code
|
||||||
func SendError(errorCode errors.Code, errorMsg string, extraParams *map[string]string) {
|
func SendErrorAndExit(errorCode errors.Code, params *map[errors.Field]string) {
|
||||||
params := map[string]string{
|
|
||||||
"message": errorMsg,
|
|
||||||
}
|
|
||||||
if extraParams != nil {
|
|
||||||
for key, value := range *extraParams {
|
|
||||||
params[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send(&errorResponse{
|
send(&errorResponse{
|
||||||
Status: "error",
|
Status: "error",
|
||||||
Code: errorCode,
|
Code: errorCode,
|
||||||
Version: version.Code,
|
Version: version.Code,
|
||||||
Params: params,
|
Params: params,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
errors.ExitWithCode(errorCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func send(data interface{}) {
|
func send(data interface{}) {
|
||||||
|
Reference in New Issue
Block a user