Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/compat/testdata/v0.1.2/export.sesh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"algorithm": "argon2id",
"salt": "517Ug4POerFZ9L9hoSnRYuONQMIgzMyxIaPtT/ixtVk=",
"ciphertext": "1FTznWDjItS4py4V/b7kOorHE3BQwxGPQzHl9Pd4IrVoUC0J5hkMXrDfvX4dZPMKXLaHuZdz8Ym4+sHzD7XmD3ZNw2n1WiY+ey/Kis+u2naCCsxr8s8AEZiJ+FgArepzAEBt0MHG6vP7N/aT3AdjTWffvntPrS5bvijNEuOlCw9LHLl5bTdpvyF32u3j59Db9ZOK083hxGUVIUuUB1cVJ9q0MXLU+UzrzKNch7Ks4nCZ9o3wogUweID45XT78PYUJbK0ZYCM8MYASJdRNqsjUw+99oyC5m/iO0WbWPb3ijn07qhGaaqAqAIaOWfXmZEcdeZPGQBFxGosneS5BpJ1iCh2IlDcZWNav2TtPygdi8fWF3DzIYpaSoMyHvdyvnxr40y4Xg808PNos96T2DrtafefiFYl82miVDpC8IwFRE5BbHxQxY10vq/BsAftVAli5BNtRwap9aQHE6/ljoG5WLFE7HBGAHMR4P3z+8TlRzrd4x0WWhUJ+uRsIqKcfJnTkn77kmGVp3DAB3VFbETYGT+h6iqi8SGoNp65xKQfupRU4MA8caGQex+La8ggOi19csWvxuqMFA1Q1tBLcT+e3NojQSyZUoqZZM51kZDz+RoYi5GFRvwA26GOYsXMg3FI4AbQeLEtRzQG+nQmoT2l9Z3KMTNLB/5GVeIVw+trGTsPtmwIDpGXYbkIqAUtPUE56M6wW2vx7eK5yibiBvMo4FCOGnEQvEmWYPBJJdb6in5mi6pPMPH6nUw2Z8hviUph21AcOWXjOSZstD1NY7zk7QFo3Yfij4wqpSQjZ2fv6chBkIkY+mW4rN2/ujLWdtRmUKAdFmWiOOR5I+7Gppk4pzbwAoI7pYLHv5JVlJRNwxiTik/+7dQPG1s+SKra1AzDx+iXwRNXiHPxaNKW2qpxvDbGr5uU1cxIBwOLCjQBlipObe2MPw7PTOd0RSZ8H6yjp1oVL8ZSbGWigXsmrAYRfwD0CUpTQvr+fHSGsa12rtLSINg7ZRrqc/bcUT6SwmPdfX8HakxlI2LycpHBWWdsEw3tyIyWaFTFDb3Ln2ZpkBptEbZAW1Jg8YFFdnoF4Kb+C9rKH04vaCf/s3sh3DDBXi/eGSmmpslUyS4c6xIgpF6AxO3Nf1hDaiDDnepmXcoLc3rTO6Rsa3SbMkCRbKS2pjxCpndhx2y7n2lHwPlSbBZJa90Sm3RIL0wj2pNqqJQa/64gWaf9O3u9oE3ZprjpAyTzr3dMd4KRGE0YnPcf2tPDjS0JD4BvldlmlrYmcn/70NcDS6WbxSCY3/Esql1Bh+gQdf/V+g1o0Rw7iO1yPRhebVFn0IH9U3TpNDpW74W0OOBgEjMTE+ppBdhWIX6lMRSh5xb2war5OY36Z0Mz9ymI4J40h54IXFjuAUZH4vPXXLVKNQAz/iExtstmgJHUCaqOsDJol2wzbSAMJrZKDJFjf4BUj8zg5rb1xK07zu1OFAKEW9MlJpPcxsiYZ+nhIbSsbhVT8U8eUtKLk3YTMF9dcqKUg9pdYRUKrM2zpd2Zq58catwujKWV4bguVmEGd3D8O2d3h1FzePTqJsjNne9Rpb3eRAh60QAzBH/4sj1i8dAUZOV1Rf3SJLxs",
"params": {
"time": 2,
"memory": 19456,
"threads": 1,
"key_len": 32
},
"version": 1
}
75 changes: 75 additions & 0 deletions internal/compat/testdata/v0.1.2/make.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash
# make.sh writes this folder's export.sesh with sesh v0.1.2, all made-up: an
# encrypted export whose entries carry earlier secrets (v0.1.2 is the first
# release whose encrypted exports hold them). It's kept as v0.1.2 wrote it;
# v012_test.go checks that today's sesh still reads it. Run it only to
# remake it, with v0.1.2:
#
# internal/compat/testdata/v0.1.2/make.sh /path/to/sesh-0.1.2
#
# Nothing personal goes in: a throwaway home for everything, made-up
# passwords, and a made-up computer name.
set -euo pipefail

sesh=$1
out=$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
"$sesh" --version | grep -q '^sesh version 0.1.2 ' || {
echo "make.sh: $sesh isn't sesh 0.1.2" >&2
exit 2
}

# Nothing from the caller's own sesh settings.
for v in $(compgen -e | grep '^SESH_' || true); do
unset "$v"
done

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
mkdir -p "$tmp/home" "$tmp/config" "$tmp/out"
export HOME="$tmp/home" XDG_CONFIG_HOME="$tmp/config"
export SESH_DB_PATH="$tmp/out/vault.db" SESH_AUTH_SOCK="$tmp/agent.sock"
export SESH_MASTER_PASSWORD=fixture-v0.1.2-master SESH_SYNC_NAME=test-laptop
export SESH_KDF_MEMORY=19MiB SESH_KDF_TIME=2 SESH_KDF_THREADS=1

# A password with two earlier ones, and a file with an earlier version under
# another name.
printf 'gh-pass-1\n' | "$sesh" add password GitHub --username maya --url https://github.com/login --folder work --tag dev
printf 'gh-pass-2\n' | "$sesh" edit password/GitHub/maya --secret
printf 'gh-pass-3\n' | "$sesh" edit password/GitHub/maya --secret
mkdir -p "$tmp/files"
printf 'apiVersion: v1\nkind: Config\n# old\n' >"$tmp/files/old.yaml"
printf 'apiVersion: v1\nkind: Config\n' >"$tmp/files/config"
"$sesh" add file kubeconfig --from "$tmp/files/old.yaml" --folder work
"$sesh" edit file/kubeconfig --from "$tmp/files/config"

# The export asks for its password at a terminal: a pseudo-terminal answers.
python3 - "$sesh" export --file "$tmp/out/export.sesh" <<'EOF'
import os, pty, select, signal, sys, time
pid, fd = pty.fork()
if pid == 0:
os.execvp(sys.argv[1], sys.argv[1:])
out, seen, deadline = b"", 0, time.monotonic() + 60
while time.monotonic() < deadline:
if not select.select([fd], [], [], 1)[0]:
continue
try:
data = os.read(fd, 4096)
except OSError:
break
if not data:
break
out += data
last = out[seen:].rstrip().lower().split(b"\n")[-1]
if b"password" in last and last.endswith(b":"):
os.write(fd, b"fixture-v0.1.2-export\n")
seen = len(out)
else:
os.kill(pid, signal.SIGKILL)
_, status = os.waitpid(pid, 0)
sys.exit(os.waitstatus_to_exitcode(status))
EOF

rm -f "$out/export.sesh"
cp "$tmp/out/export.sesh" "$out/"
chmod u=rw,go=r "$out/export.sesh"
echo "Wrote $out/export.sesh"
91 changes: 91 additions & 0 deletions internal/compat/v012_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package compat

import (
"bytes"
"os"
"path/filepath"
"testing"

"github.com/bashhack/sesh/internal/importer/seshexport"
"github.com/bashhack/sesh/internal/password"
"github.com/bashhack/sesh/internal/vault"
)

// What v0.1.2's export was given (testdata/v0.1.2/make.sh): GitHub's
// password with two earlier ones, and a file with an earlier version
// under another name.
const exportPasswordV012 = "fixture-v0.1.2-export"

var (
kubeNowV012 = "apiVersion: v1\nkind: Config\n"
kubeEarlierV012 = "apiVersion: v1\nkind: Config\n# old\n"
)

// An encrypted export v0.1.2 wrote, the first to hold earlier secrets, imports into a new vault with them: their
// order, when each was replaced and began, and a file's earlier name.
func TestExportV012(t *testing.T) {
data, err := os.ReadFile(filepath.Join("testdata", "v0.1.2", "export.sesh"))
if err != nil {
t.Fatal(err)
}
sealed, err := password.ReadSealed(bytes.NewReader(data))
if err != nil {
t.Fatal(err)
}
list, err := sealed.Entries([]byte(exportPasswordV012))
if err != nil {
t.Fatal(err)
}
st, _ := open(t, filepath.Join(t.TempDir(), "new.db"), "a-new-vault-password")
st.SetHistoryKeep(10)
found := map[vault.Key]bool{}
for _, e := range seshexport.Entries(list) {
if e.Skip != "" {
t.Fatalf("%v skipped: %s", e.Key, e.Skip)
}
found[e.Key] = true
for _, h := range e.Earlier {
if h.ReplacedAt.IsZero() || h.SetAt.IsZero() {
t.Errorf("%v: an earlier secret without its times: %+v", e.Key, h)
}
}
ent := vault.Entry{Key: e.Key, Folder: e.Folder, Tags: e.Tags, Settings: e.Settings, CreatedAt: e.Created, UpdatedAt: e.Updated}
if _, err := st.SaveImported(&ent, e.Secret, &e.Details, e.Earlier); err != nil {
t.Fatalf("%v: %v", e.Key, err)
}
}
if !found[github] || !found[kube] || len(found) != 2 {
t.Fatalf("entries %v", found)
}

for i, want := range append([]string{"gh-pass-3"}, githubEarlier...) {
var got []byte
var err error
if i == 0 {
got, err = st.Get(github)
} else {
got, err = st.ReadVersion(github, i+1, "compat test")
}
if err != nil || string(got) != want {
t.Errorf("GitHub's version %d: %q, %v; want %q", i+1, got, err, want)
}
}

e, err := st.Lookup(kube)
if err != nil {
t.Fatal(err)
}
if got, err := st.Get(kube); err != nil || string(got) != kubeNowV012 || e.Settings.FileName != "config" {
t.Errorf("kubeconfig now: %q named %q (%v)", got, e.Settings.FileName, err)
}
if _, err := st.RestoreVersion(kube, 2); err != nil {
t.Fatal(err)
}
e, err = st.Lookup(kube)
if err != nil {
t.Fatal(err)
}
if got, err := st.Get(kube); err != nil || string(got) != kubeEarlierV012 || e.Settings.FileName != "old.yaml" {
t.Errorf("kubeconfig's earlier version, restored: %q named %q (%v)", got, e.Settings.FileName, err)
}
}
Loading