diff --git a/cli/cmd/smcli/api.go b/cli/cmd/smcli/api.go index 49569eb..0c8fc43 100644 --- a/cli/cmd/smcli/api.go +++ b/cli/cmd/smcli/api.go @@ -17,10 +17,12 @@ import ( ) type Client struct { - Server string // e.g. https://pwvault.turnsys.com - HTTP *http.Client - Email string - Password string + Server string // e.g. https://pwvault.turnsys.com + HTTP *http.Client + Email string + Password string + TOTPSecret string + reloginDone bool AccessToken string RefreshToken string @@ -180,7 +182,7 @@ func (c *Client) Login() error { if t.AccessToken == "" { // 2FA retry path (provider 0 = authenticator TOTP) if strings.Contains(string(out), "Two factor required") { - secret := os.Getenv("SM_TOTP_SECRET") + secret := c.TOTPSecret if secret != "" { code, terr := totpNow(secret, time.Now()) if terr != nil { @@ -327,3 +329,31 @@ func (c *Client) DeleteCipher(id string) error { _, _ = c.api("PUT", "/api/ciphers/"+id+"/purge", map[string]any{}, true) return nil } + +// selfRelogin performs the full login+unlock using SM_* env credentials +// (injected by the sm shims from the TSGCOO vault-account env). Saves state. +func (c *Client) selfRelogin() error { + if c.Password == "" { + c.Password = os.Getenv("SM_PASSWORD") + } + if c.TOTPSecret == "" { + c.TOTPSecret = os.Getenv("SM_TOTP_SECRET") + } + if c.Password == "" { + return errors.New("relogin unavailable: SM_PASSWORD not set") + } + if err := c.Login(); err != nil { + return err + } + if err := c.Unlock(); err != nil { + return err + } + if s, err := loadState(); err == nil { + s.AccessToken = c.AccessToken + s.UserSymKey = toHex(c.UserSymKey) + s.StretchedKey = toHex(c.StretchedKey) + s.MasterKey = toHex(c.MasterKey) + _ = saveState(s) + } + return nil +} diff --git a/cli/cmd/smcli/main.go b/cli/cmd/smcli/main.go index 5e5bfb7..246254a 100644 --- a/cli/cmd/smcli/main.go +++ b/cli/cmd/smcli/main.go @@ -96,6 +96,7 @@ func loadState() (*State, error) { func newClientFromState(s *State) (*Client, error) { c := &Client{ Server: s.Server, Email: s.Email, + Password: os.Getenv("SM_PASSWORD"), TOTPSecret: os.Getenv("SM_TOTP_SECRET"), AccessToken: s.AccessToken, RefreshToken: s.RefreshToken, KDFType: s.KDFType, KDFIter: s.KDFIter, KDFMemory: s.KDFMemory, KDFParallel: s.KDFParallel, HTTP: &http.Client{Timeout: 30 * time.Second}, @@ -114,15 +115,16 @@ func newClientFromState(s *State) (*Client, error) { } func cmdLogin(server, email, password string) error { - c := &Client{Server: server, Email: email, Password: password, + c := &Client{Server: server, Email: email, Password: password, TOTPSecret: os.Getenv("SM_TOTP_SECRET"), HTTP: &http.Client{Timeout: 30 * time.Second}} if err := c.Login(); err != nil { return err } s := &State{ Version: stateVersion, Server: server, Email: email, - AccessToken: c.AccessToken, RefreshToken: c.RefreshToken, - KDFType: c.KDFType, KDFIter: c.KDFIter, KDFMemory: c.KDFMemory, KDFParallel: c.KDFParallel, + AccessToken: c.AccessToken, + RefreshToken: c.RefreshToken, + KDFType: c.KDFType, KDFIter: c.KDFIter, KDFMemory: c.KDFMemory, KDFParallel: c.KDFParallel, MasterKey: toHex(c.MasterKey), StretchedKey: toHex(c.StretchedKey), } diff --git a/cli/smcli b/cli/smcli index f42fb64..777587b 100755 Binary files a/cli/smcli and b/cli/smcli differ diff --git a/docker/compose.yaml b/docker/compose.yaml index 9272a78..a4318d9 100644 --- a/docker/compose.yaml +++ b/docker/compose.yaml @@ -10,7 +10,7 @@ name: knel-secretsmanager services: smcli: - image: git.knownelement.com/knel/knel-secretsmanager-cli@sha256:46d80c0a0ef53a9303dd54b3799a64a61cd4e4dc892282bc4d8a220378117ce9 + image: git.knownelement.com/knel/knel-secretsmanager-cli@sha256:8abfc55dfa7ca9e70b286a249b7ca823531bd55da29bed70d3354a58ec4d8fec container_name: ukrrs-secretsmgr-cli restart: unless-stopped entrypoint: ["sleep", "infinity"]