Implement list
action (#12)
This commit is contained in:
11
Gopkg.lock
generated
11
Gopkg.lock
generated
@@ -1,6 +1,15 @@
|
|||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mattn/go-zglob"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"fastwalk"
|
||||||
|
]
|
||||||
|
revision = "4959821b481786922ac53e7ef25c61ae19fb7c36"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/rifflock/lfshook"
|
name = "github.com/rifflock/lfshook"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
@@ -34,6 +43,6 @@
|
|||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "f6199a143c790c5c1422bd35477ede08e5d2e3a0e5552d769e7c4de6ed8a14b1"
|
inputs-digest = "1f59ddaed2db7de2b34f8485550888fa1cb625342398af10acb68e5ee227f3f8"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
@@ -27,3 +27,7 @@
|
|||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/rifflock/lfshook"
|
name = "github.com/rifflock/lfshook"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/mattn/go-zglob"
|
||||||
|
24
PROTOCOL.md
24
PROTOCOL.md
@@ -41,16 +41,18 @@ 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 | error |
|
||||||
| 11 | Unable to parse browser request | error |
|
| 11 | Unable to parse browser request | error |
|
||||||
| 12 | Invalid request action | action |
|
| 12 | Invalid request action | action |
|
||||||
| 13 | Inaccessible user-configured password store | error, name, path |
|
| 13 | Inaccessible user-configured password store | error, name, path |
|
||||||
| 14 | Inaccessible default password store | error, path |
|
| 14 | Inaccessible default password store | error, path |
|
||||||
| 15 | Unable to determine the location of the default password store | error |
|
| 15 | Unable to determine the location of the default password store | 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 | error, name, path |
|
||||||
| 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 | error, path |
|
||||||
|
| 18 | Unable to list files in a password store | error, name, path |
|
||||||
|
| 19 | Unable to determine a relative path for a file in a password store | error, file, name, path |
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
@@ -171,7 +173,7 @@ Get the decrypted contents of a specific file.
|
|||||||
"status": "ok",
|
"status": "ok",
|
||||||
"version": <int>,
|
"version": <int>,
|
||||||
"data": {
|
"data": {
|
||||||
"data": "<decrypted file contents>"
|
"contents": "<decrypted file contents>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@@ -33,6 +33,12 @@ const (
|
|||||||
|
|
||||||
// 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 = 17
|
||||||
|
|
||||||
|
// CodeUnableToListFilesInPasswordStore error listing files in a password store
|
||||||
|
CodeUnableToListFilesInPasswordStore = 18
|
||||||
|
|
||||||
|
// CodeUnableToDetermineRelativeFilePathInPasswordStore error determining a relative path for a file in a password store
|
||||||
|
CodeUnableToDetermineRelativeFilePathInPasswordStore = 19
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExitWithCode exit with error code
|
// ExitWithCode exit with error code
|
||||||
|
@@ -16,7 +16,7 @@ function require()
|
|||||||
if ! `command -v "$1" >/dev/null`; then
|
if ! `command -v "$1" >/dev/null`; then
|
||||||
OUTPUT="{\n \"status\": \"error\"\n "version": $VERSION,\n \"params\": {\n \"message\": \"Required dependency '$1' is missing\"\n }, \"code\": 1\n}"
|
OUTPUT="{\n \"status\": \"error\"\n "version": $VERSION,\n \"params\": {\n \"message\": \"Required dependency '$1' is missing\"\n }, \"code\": 1\n}"
|
||||||
LANG=C LC_ALL=C LENGTH=${#OUTPUT}
|
LANG=C LC_ALL=C LENGTH=${#OUTPUT}
|
||||||
echo -n
|
echo -n
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -94,11 +94,11 @@ function configure()
|
|||||||
done
|
done
|
||||||
|
|
||||||
[ -n "$PASSWORD_STORE_DIR" ] || PASSWORD_STORE_DIR="~/.password-store"
|
[ -n "$PASSWORD_STORE_DIR" ] || PASSWORD_STORE_DIR="~/.password-store"
|
||||||
OUTPUT="$(jq -n --arg defaultPath "$PASSWORD_STORE_DIR" '.defaultPath = $defaultPath')"
|
OUTPUT="$(jq -n --arg defaultPath "$PASSWORD_STORE_DIR" '.defaultStore.path = $defaultPath')"
|
||||||
|
|
||||||
STOREPATH=$(echo "$PASSWORD_STORE_DIR" | sed 's/^~/$HOME/' | envsubst)
|
STOREPATH=$(echo "$PASSWORD_STORE_DIR" | sed 's/^~/$HOME/' | envsubst)
|
||||||
if [ -f "$STOREPATH/.browserpass.json" ]; then
|
if [ -f "$STOREPATH/.browserpass.json" ]; then
|
||||||
OUTPUT=$(jq --arg settings "$(cat "$STOREPATH/.browserpass.json")" '.defaultSettings = $settings' <<< "$OUTPUT")
|
OUTPUT=$(jq --arg settings "$(cat "$STOREPATH/.browserpass.json")" '.defaultStore.settings = $settings' <<< "$OUTPUT")
|
||||||
else
|
else
|
||||||
OUTPUT=$(jq '.defaultSettings = ""' <<< "$OUTPUT")
|
OUTPUT=$(jq '.defaultSettings = ""' <<< "$OUTPUT")
|
||||||
fi
|
fi
|
||||||
@@ -153,9 +153,9 @@ function fetch()
|
|||||||
# get file contents
|
# get file contents
|
||||||
[ -f "$FILEPATH" ] || fail "Requested file does not exist: $STORE:$FILE"
|
[ -f "$FILEPATH" ] || fail "Requested file does not exist: $STORE:$FILE"
|
||||||
DATA="$(gpg -q --decrypt "$FILEPATH")"
|
DATA="$(gpg -q --decrypt "$FILEPATH")"
|
||||||
|
|
||||||
# build output
|
# build output
|
||||||
echo "$(jq -n --arg data "$DATA" '.data = $data')"
|
echo "$(jq -n --arg data "$DATA" '.contents = $data')"
|
||||||
}
|
}
|
||||||
|
|
||||||
function run()
|
function run()
|
||||||
|
69
request/list.go
Normal file
69
request/list.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package request
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/browserpass/browserpass-native/errors"
|
||||||
|
"github.com/browserpass/browserpass-native/response"
|
||||||
|
"github.com/mattn/go-zglob"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func listFiles(request request) {
|
||||||
|
responseData := response.MakeListResponse()
|
||||||
|
|
||||||
|
for _, store := range request.Settings.Stores {
|
||||||
|
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.SendError(
|
||||||
|
errors.CodeInaccessiblePasswordStore,
|
||||||
|
"The password store is not accessible",
|
||||||
|
&map[string]string{"error": err.Error(), "name": store.Name, "path": store.Path},
|
||||||
|
)
|
||||||
|
errors.ExitWithCode(errors.CodeInaccessiblePasswordStore)
|
||||||
|
}
|
||||||
|
|
||||||
|
store.Path = normalizedStorePath
|
||||||
|
|
||||||
|
files, err := zglob.GlobFollowSymlinks(filepath.Join(store.Path, "/**/*.gpg"))
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(
|
||||||
|
"Unable to list the files in the password store '%v' at the location '%v': %+v",
|
||||||
|
store.Name, store.Path, err,
|
||||||
|
)
|
||||||
|
response.SendError(
|
||||||
|
errors.CodeUnableToListFilesInPasswordStore,
|
||||||
|
"Unable to list the files in the password store",
|
||||||
|
&map[string]string{"error": err.Error(), "name": store.Name, "path": store.Path},
|
||||||
|
)
|
||||||
|
errors.ExitWithCode(errors.CodeUnableToListFilesInPasswordStore)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, file := range files {
|
||||||
|
relativePath, err := filepath.Rel(store.Path, file)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf(
|
||||||
|
"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,
|
||||||
|
)
|
||||||
|
response.SendError(
|
||||||
|
errors.CodeUnableToDetermineRelativeFilePathInPasswordStore,
|
||||||
|
"Unable to determine the relative path for a file in the password store",
|
||||||
|
&map[string]string{"error": err.Error(), "file": file, "name": store.Name, "path": store.Path},
|
||||||
|
)
|
||||||
|
errors.ExitWithCode(errors.CodeUnableToDetermineRelativeFilePathInPasswordStore)
|
||||||
|
}
|
||||||
|
files[i] = relativePath
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(files)
|
||||||
|
responseData.Files[store.Name] = files
|
||||||
|
}
|
||||||
|
|
||||||
|
response.SendOk(responseData)
|
||||||
|
}
|
@@ -31,7 +31,7 @@ func Process() {
|
|||||||
case "configure":
|
case "configure":
|
||||||
configure(request)
|
configure(request)
|
||||||
case "list":
|
case "list":
|
||||||
break
|
listFiles(request)
|
||||||
case "fetch":
|
case "fetch":
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
|
@@ -40,6 +40,18 @@ func MakeConfigureResponse() *ConfigureResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListResponse a response format for the "list" request
|
||||||
|
type ListResponse struct {
|
||||||
|
Files map[string][]string `json:"files"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeListResponse initializes an empty list response
|
||||||
|
func MakeListResponse() *ListResponse {
|
||||||
|
return &ListResponse{
|
||||||
|
Files: make(map[string][]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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{
|
||||||
|
Reference in New Issue
Block a user