commit 18d131176b593d1f53af52c556836d2c94e24df0
parent 34cc44911425161f481f9fd590a720cea99ee2a2
Author: Sean Enck <sean@ttypty.com>
Date: Tue, 25 Jul 2023 18:24:24 -0400
support a shortened hash
Diffstat:
8 files changed, 119 insertions(+), 11 deletions(-)
diff --git a/internal/backend/query.go b/internal/backend/query.go
@@ -126,6 +126,13 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) {
}
jsonMode = m
}
+ var hashLength int
+ if jsonMode == inputs.JSONDataOutputHash {
+ hashLength, err = inputs.GetHashLength()
+ if err != nil {
+ return nil, err
+ }
+ }
var results []QueryEntity
for _, k := range keys {
entity := QueryEntity{Path: k}
@@ -146,6 +153,9 @@ func (t *Transaction) QueryCallback(args QueryOptions) ([]QueryEntity, error) {
data = val
case inputs.JSONDataOutputHash:
data = fmt.Sprintf("%x", sha512.Sum512([]byte(val)))
+ if hashLength > 0 && len(data) > hashLength {
+ data = data[0:hashLength]
+ }
}
t := getValue(e.backing, modTimeKey)
s := JSON{ModTime: t, Data: data}
diff --git a/internal/backend/query_test.go b/internal/backend/query_test.go
@@ -96,6 +96,19 @@ func TestValueModes(t *testing.T) {
if len(m.ModTime) < 20 {
t.Errorf("invalid date/time")
}
+ os.Setenv("LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH", "10")
+ defer os.Clearenv()
+ q, err = fullSetup(t, true).Get("test/test/abc", backend.JSONValue)
+ if err != nil {
+ t.Errorf("no error: %v", err)
+ }
+ m = backend.JSON{}
+ if err := json.Unmarshal([]byte(q.Value), &m); err != nil {
+ t.Errorf("no error: %v", err)
+ }
+ if m.Data != "44276ba24d" {
+ t.Errorf("invalid result value: %s", q.Value)
+ }
q, err = fullSetup(t, true).Get("test/test/ab11c", backend.SecretValue)
if err != nil {
t.Errorf("no error: %v", err)
diff --git a/internal/cli/core_test.go b/internal/cli/core_test.go
@@ -14,7 +14,7 @@ func TestUsage(t *testing.T) {
t.Errorf("invalid usage, out of date? %d", len(u))
}
u, _ = cli.Usage(true)
- if len(u) != 94 {
+ if len(u) != 95 {
t.Errorf("invalid verbose usage, out of date? %d", len(u))
}
for _, usage := range u {
diff --git a/internal/inputs/env.go b/internal/inputs/env.go
@@ -68,6 +68,8 @@ const (
MaxTOTPTimeDefault = "120"
// JSONDataOutputEnv controls how JSON is output
JSONDataOutputEnv = prefixKey + "JSON_DATA_OUTPUT"
+ defaultHashLength = 0
+ hashJSONLengthEnv = JSONDataOutputEnv + "_HASH_LENGTH"
)
var isYesNoArgs = []string{system.Yes, system.No}
@@ -122,19 +124,39 @@ func GetReKey(args []string) ([]string, error) {
// GetClipboardMax will get max time to keep an entry in the clipboard before clearing
func GetClipboardMax() (int, error) {
- max := defaultMaxClipboard
- useMax := os.Getenv(clipMaxEnv)
- if useMax != "" {
- i, err := strconv.Atoi(useMax)
+ return getPositiveIntEnv(defaultMaxClipboard, clipMaxEnv, "clipboard max time", false)
+}
+
+// GetHashLength will get the maximum hash length allowed in JSON output hashing mode
+func GetHashLength() (int, error) {
+ return getPositiveIntEnv(defaultHashLength, hashJSONLengthEnv, "hash length", true)
+}
+
+func getPositiveIntEnv(defaultVal int, key, desc string, canBeZero bool) (int, error) {
+ val := defaultVal
+ use := os.Getenv(key)
+ if use != "" {
+ i, err := strconv.Atoi(use)
if err != nil {
return -1, err
}
- if i < 1 {
- return -1, errors.New("clipboard max time must be greater than 0")
+ invalid := false
+ check := ""
+ if canBeZero {
+ check = "="
+ }
+ switch i {
+ case 0:
+ invalid = !canBeZero
+ default:
+ invalid = i < 0
+ }
+ if invalid {
+ return -1, fmt.Errorf("%s must be >%s 0", desc, check)
}
- max = i
+ val = i
}
- return max, nil
+ return val, nil
}
// GetKey will get the encryption key setup for lb
@@ -280,5 +302,6 @@ func ListEnvironmentVariables(showValues bool) []string {
results = append(results, e.formatEnvironmentVariable(false, KeyFileEnv, "", "additional keyfile to access/protect the database", []string{"keyfile"}))
results = append(results, e.formatEnvironmentVariable(false, ModTimeEnv, ModTimeFormat, fmt.Sprintf("input modification time to set for the entry\n(expected format: %s)", ModTimeFormat), []string{"modtime"}))
results = append(results, e.formatEnvironmentVariable(false, JSONDataOutputEnv, string(JSONDataOutputHash), fmt.Sprintf("changes what the data field in JSON outputs will contain\nuse '%s' with CAUTION", JSONDataOutputRaw), []string{string(JSONDataOutputRaw), string(JSONDataOutputHash), string(JSONDataOutputBlank)}))
+ results = append(results, e.formatEnvironmentVariable(false, hashJSONLengthEnv, fmt.Sprintf("%d", defaultHashLength), fmt.Sprintf("maximum hash length the JSON output should contain\nwhen '%s' mode is set for JSON output", JSONDataOutputHash), []string{"integer"}))
return results
}
diff --git a/internal/inputs/env_test.go b/internal/inputs/env_test.go
@@ -112,7 +112,7 @@ func TestListVariables(t *testing.T) {
known[trim] = struct{}{}
}
l := len(known)
- if l != 21 {
+ if l != 22 {
t.Errorf("invalid env count, outdated? %d", l)
}
}
@@ -145,3 +145,56 @@ func TestReKey(t *testing.T) {
os.Setenv("LOCKBOX_KEY_NEW", "")
os.Setenv("LOCKBOX_KEYFILE_NEW", "")
}
+
+func TestGetClipboardMax(t *testing.T) {
+ os.Setenv("LOCKBOX_CLIP_MAX", "")
+ defer os.Clearenv()
+ max, err := inputs.GetClipboardMax()
+ if err != nil || max != 45 {
+ t.Error("invalid clipboard read")
+ }
+ os.Setenv("LOCKBOX_CLIP_MAX", "1")
+ max, err = inputs.GetClipboardMax()
+ if err != nil || max != 1 {
+ t.Error("invalid clipboard read")
+ }
+ os.Setenv("LOCKBOX_CLIP_MAX", "-1")
+ if _, err := inputs.GetClipboardMax(); err == nil || err.Error() != "clipboard max time must be > 0" {
+ t.Errorf("invalid err: %v", err)
+ }
+ os.Setenv("LOCKBOX_CLIP_MAX", "alk;ja")
+ if _, err := inputs.GetClipboardMax(); err == nil || err.Error() != "strconv.Atoi: parsing \"alk;ja\": invalid syntax" {
+ t.Errorf("invalid err: %v", err)
+ }
+ os.Setenv("LOCKBOX_CLIP_MAX", "0")
+ if _, err := inputs.GetClipboardMax(); err == nil || err.Error() != "clipboard max time must be > 0" {
+ t.Errorf("invalid err: %v", err)
+ }
+}
+
+func TestGetHashLength(t *testing.T) {
+ os.Setenv("LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH", "")
+ defer os.Clearenv()
+ val, err := inputs.GetHashLength()
+ if err != nil || val != 0 {
+ t.Error("invalid hash read")
+ }
+ os.Setenv("LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH", "1")
+ val, err = inputs.GetHashLength()
+ if err != nil || val != 1 {
+ t.Error("invalid hash read")
+ }
+ os.Setenv("LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH", "0")
+ val, err = inputs.GetHashLength()
+ if err != nil || val != 0 {
+ t.Error("invalid hash read")
+ }
+ os.Setenv("LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH", "-1")
+ if _, err := inputs.GetHashLength(); err == nil || err.Error() != "hash length must be >= 0" {
+ t.Errorf("invalid err: %v", err)
+ }
+ os.Setenv("LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH", "-aoaofaij;p1")
+ if _, err := inputs.GetHashLength(); err == nil || err.Error() != "strconv.Atoi: parsing \"-aoaofaij;p1\": invalid syntax" {
+ t.Errorf("invalid err: %v", err)
+ }
+}
diff --git a/internal/platform/clipboard_test.go b/internal/platform/clipboard_test.go
@@ -41,7 +41,7 @@ func TestMaxTime(t *testing.T) {
}
os.Setenv("LOCKBOX_CLIP_MAX", "-1")
_, err = platform.NewClipboard()
- if err == nil || err.Error() != "clipboard max time must be greater than 0" {
+ if err == nil || err.Error() != "clipboard max time must be > 0" {
t.Errorf("invalid max time error: %v", err)
}
os.Setenv("LOCKBOX_CLIP_MAX", "$&(+")
diff --git a/tests/expected.log b/tests/expected.log
@@ -155,5 +155,11 @@ test2
"modtime": "XXXX-XX-XX",
}
}
+{
+ "keys/k/one2": {
+ "modtime": "XXXX-XX-XX",
+ "data": "6d2"
+ }
+}
clipboard will clear in 5 seconds
Wrong password? HMAC-SHA256 of header mismatching
diff --git a/tests/run.sh b/tests/run.sh
@@ -115,6 +115,9 @@ _rekey() {
${LB_BINARY} json k
export LOCKBOX_JSON_DATA_OUTPUT=empty
${LB_BINARY} json k
+ export LOCKBOX_JSON_DATA_OUTPUT=hash
+ export LOCKBOX_JSON_DATA_OUTPUT_HASH_LENGTH=3
+ ${LB_BINARY} json k
}
_clipboard() {