Skip to content

Commit

Permalink
Add shelly set-user-ca
Browse files Browse the repository at this point in the history
  • Loading branch information
jcodybaker committed Feb 20, 2024
1 parent a2cbc52 commit 7a8b553
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 79 deletions.
78 changes: 0 additions & 78 deletions cmd/shelly.go

This file was deleted.

77 changes: 77 additions & 0 deletions cmd/shelly_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cmd

import (
"fmt"

"github.com/jcodybaker/go-shelly"
"github.com/jcodybaker/shellyctl/pkg/discovery"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
shellyAuthCmd = &cobra.Command{
Use: "set-auth",
RunE: shellyAuthCmdRunE,
}
)

func init() {
shellyAuthCmd.Flags().String(
"password", "", "password to use for auth. If empty, the password will be cleared.",
)
shellyComponent.Parent.AddCommand(shellyAuthCmd)
discoveryFlags(shellyAuthCmd.Flags(), discoveryFlagsOptions{interactive: true})
}

func shellyAuthCmdRunE(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
ll := log.Ctx(ctx).With().Str("request", (&shelly.ShellySetAuthRequest{}).Method()).Logger()
dOpts, err := discoveryOptionsFromFlags(cmd.Flags())
if err != nil {
ll.Fatal().Err(err).Msg("parsing flags")
}

password := viper.GetString("password")

discoverer := discovery.NewDiscoverer(dOpts...)
if err := discoveryAddDevices(ctx, discoverer); err != nil {
ll.Fatal().Err(err).Msg("adding devices")
}

if _, err := discoverer.Search(ctx); err != nil {
return err
}

for _, d := range discoverer.AllDevices() {
ll := d.Log(ll)
conn, err := d.Open(ctx)
if err != nil {
return err
}
defer func() {
if err := conn.Disconnect(ctx); err != nil {
ll.Warn().Err(err).Msg("disconnecting from device")
}
}()
req, err := shelly.BuildShellyAuthRequest(ctx, conn, password)
if err != nil {
return fmt.Errorf("building %s request: %w", req.Method(), err)
}
ll.Info().Any("request_body", req).Str("method", req.Method()).Msg("sending request")
resp := req.NewResponse()
raw, err := shelly.Do(ctx, conn, d.AuthCallback(ctx), req, resp)
if err != nil {
return fmt.Errorf("executing %s: %w", req.Method(), err)
}
Output(
ctx,
fmt.Sprintf("Response to %s command for %s", req.Method(), d.BestName()),
"response",
resp,
raw.Response,
)
}
return nil
}
152 changes: 152 additions & 0 deletions cmd/shelly_set_user_ca.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package cmd

import (
"bufio"
"bytes"
"errors"
"io"
"os"

"github.com/jcodybaker/go-shelly"
"github.com/jcodybaker/shellyctl/pkg/discovery"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var (
shellyPutUserCACmd = &cobra.Command{
Use: "put-user-ca",
RunE: shellyPutUserCACmdRunE,
}
)

func init() {
// Passing a whole cert as a cmd argument is awkward, but viper supports config files which
// should facilitate multi-line strings in yaml, JSON, etc.
shellyPutUserCACmd.Flags().String(
"ca-data", "", "PEM encoded certificate authority data. (either --ca-data OR --ca-data-file is required)",
)
shellyPutUserCACmd.Flags().String(
"ca-data-file", "", "path to a file containing PEM encoded certificate authority data.",
)
shellyPutUserCACmd.Flags().Bool(
"remove-ca", false, "remove an existing CA certificate from the device",
)
shellyComponent.Parent.AddCommand(shellyPutUserCACmd)
discoveryFlags(shellyPutUserCACmd.Flags(), discoveryFlagsOptions{interactive: true})
}

func shellyPutUserCACmdRunE(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
ll := log.Ctx(ctx).With().Str("request", (&shelly.ShellyPutUserCARequest{}).Method()).Logger()

var b *bytes.Buffer
data := viper.GetString("ca-data")
dataFile := viper.GetString("ca-data-file")
remove := viper.GetBool("remove-ca")
if (data != "" && dataFile != "") || (data != "" && remove) || (dataFile != "" && remove) {
return errors.New("--ca-data, --ca-data-file, and --remove-ca options are mutually exclusive")
}
if data == "" && dataFile == "" && !remove {
return errors.New("exactly one of `--ca-data`, `--ca-data-file`, or `--remove-ca` options are required")
}
if data != "" {
b = bytes.NewBufferString(data)
} else if dataFile == "-" {
b = &bytes.Buffer{}
if _, err := io.Copy(b, os.Stdin); err != nil {
ll.Fatal().Err(err).Msg("reading stdin for --ca-data-file")
}
} else if dataFile != "" {
b = &bytes.Buffer{}
f, err := os.Open(dataFile)
if err != nil {
ll.Fatal().Err(err).Str("ca-data-file", dataFile).Msg("reading --ca-data-file")
}
n, err := io.Copy(b, f)
if err != nil {
ll.Fatal().Err(err).Str("ca-data-file", dataFile).Msg("reading --ca-data-file")
}
ll.Debug().Int64("bytes_read", n).Str("ca-data-file", dataFile).Msg("finished reading --ca-data-file")
if err := f.Close(); err != nil {
ll.Warn().Err(err).Str("ca-data-file", dataFile).Msg("closing --ca-data-file")
}
}

dOpts, err := discoveryOptionsFromFlags(cmd.Flags())
if err != nil {
ll.Fatal().Err(err).Msg("parsing flags")
}

discoverer := discovery.NewDiscoverer(dOpts...)
if err := discoveryAddDevices(ctx, discoverer); err != nil {
ll.Fatal().Err(err).Msg("adding devices")
}

if _, err := discoverer.Search(ctx); err != nil {
return err
}

for _, d := range discoverer.AllDevices() {
ll := d.Log(ll)
conn, err := d.Open(ctx)
if err != nil {
return err
}
defer func() {
if err := conn.Disconnect(ctx); err != nil {
ll.Warn().Err(err).Msg("disconnecting from device")
}
}()
if remove {
req := &shelly.ShellyPutUserCARequest{}
ll.Debug().
Str("method", req.Method()).
Any("request_body", req).
Msg("sending request to clear data")
_, _, err := req.Do(ctx, conn, d.AuthCallback(ctx))
if err != nil {
if viper.GetBool("skip-failed-hosts") {
ll.Err(err).Msg("error executing request; contining because --skip-failed-hosts=true")
continue
} else {
ll.Fatal().Err(err).Msg("error executing request")
}
}
ll.Info().Str("method", req.Method()).Msg("successfully cleared data")
continue
}
s := bufio.NewScanner(b)
req := &shelly.ShellyPutUserCARequest{}
var line int
for s.Scan() {
line++
req.Data = shelly.StrPtr(s.Text())
req.Append = line > 1
ll.Debug().
Str("method", req.Method()).
Int("line", line).
Any("request_body", req).
Msg("sending data")
if _, _, err := req.Do(ctx, conn, d.AuthCallback(ctx)); err != nil {
return err
}
ll.Debug().
Str("method", req.Method()).
Int("line", line).
Any("request_body", req).
Msg("request succeeded")
}
if err := s.Err(); err != nil {
// We're reading memory buffered data here, so this isn't likely an emphermal IO failure
// but rather something like line larger than the buffer size.
ll.Fatal().Err(err).Str("method", req.Method()).Msg("reading input data")
}
ll.Info().
Str("method", req.Method()).
Int("lines", line).
Msg("upload succeeded")
}
return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21.3
require (
github.com/go-logr/zerologr v1.2.3
github.com/hashicorp/mdns v1.0.5
github.com/jcodybaker/go-shelly v0.0.0-20240219065811-567c6d96a3af
github.com/jcodybaker/go-shelly v0.0.0-20240219095728-be65a682916b
github.com/mongoose-os/mos v0.0.0-20230313140341-b44964e63a92
github.com/prometheus/client_golang v1.18.0
github.com/rs/zerolog v1.31.0
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,12 @@ github.com/jcodybaker/go-shelly v0.0.0-20240219062609-517f47e8956c h1:OMMo81Cy88
github.com/jcodybaker/go-shelly v0.0.0-20240219062609-517f47e8956c/go.mod h1:EfKnkqHSomR+wV7AoVgv6wU+kz1Xm4RSaEKaWMKWgWg=
github.com/jcodybaker/go-shelly v0.0.0-20240219065811-567c6d96a3af h1:SZTxDEPrJ5/Dj/0ZLhc0s9N9m86ByTVdQsYp9F+P/zA=
github.com/jcodybaker/go-shelly v0.0.0-20240219065811-567c6d96a3af/go.mod h1:EfKnkqHSomR+wV7AoVgv6wU+kz1Xm4RSaEKaWMKWgWg=
github.com/jcodybaker/go-shelly v0.0.0-20240219080355-db595c39c545 h1:FV5qJbu5NsYASA45ts78BOhiiGSqkkeJ3/3wwXgk1Go=
github.com/jcodybaker/go-shelly v0.0.0-20240219080355-db595c39c545/go.mod h1:EfKnkqHSomR+wV7AoVgv6wU+kz1Xm4RSaEKaWMKWgWg=
github.com/jcodybaker/go-shelly v0.0.0-20240219095047-15d8021c50d7 h1:cWn6PcVFIqM7GdZmFFGxV4zQHfSKu0KmvmSxEMn+HKo=
github.com/jcodybaker/go-shelly v0.0.0-20240219095047-15d8021c50d7/go.mod h1:EfKnkqHSomR+wV7AoVgv6wU+kz1Xm4RSaEKaWMKWgWg=
github.com/jcodybaker/go-shelly v0.0.0-20240219095728-be65a682916b h1:Qsp0H62AbXVZ8b2MXfy5vmnw4TDDCr388TAa2ShMGBA=
github.com/jcodybaker/go-shelly v0.0.0-20240219095728-be65a682916b/go.mod h1:EfKnkqHSomR+wV7AoVgv6wU+kz1Xm4RSaEKaWMKWgWg=
github.com/jcodybaker/mdns v0.0.0-20240218225721-3b8606993b85 h1:/Ls0Q1POaNRFf9uopWlac5skKmWCkEwn/EPmueN5Mco=
github.com/jcodybaker/mdns v0.0.0-20240218225721-3b8606993b85/go.mod h1:RBWesCDwuRmyqepO+WxO8JSfrh3Tj3LkSzXPQlFq2nM=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
Expand Down

0 comments on commit 7a8b553

Please sign in to comment.