Automatically detect piped stdin on the root command; it doubles as input and output
This commit is contained in:
parent
3470117c31
commit
505e0e4b41
8 changed files with 71 additions and 125 deletions
|
|
@ -1,42 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/AYM1607/ccclip/internal/configfile"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(getClipboardCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getClipboardCmd = &cobra.Command{
|
|
||||||
Use: "get-clipboard",
|
|
||||||
Short: "get the currently stored clipboard",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
cc, err := configfile.EnsureAndGet()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cc.DeviceId == "" {
|
|
||||||
return errors.New("you must log in and register your device")
|
|
||||||
}
|
|
||||||
pvk, err := configfile.LoadPrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not load this device's private key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
plain, err := apiclient.GetClipboard(cc.DeviceId, pvk)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not set clipboard: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Your current clipbard is:")
|
|
||||||
fmt.Fprintf(os.Stdout, plain)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(getDevicesCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
var getDevicesCmd = &cobra.Command{
|
|
||||||
Use: "get-devices",
|
|
||||||
Short: "Register a user with a given email and password",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
// cc, err := configfile.EnsureAndGet()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if cc.DeviceId == "" {
|
|
||||||
// return errors.New("your device is not registered")
|
|
||||||
// }
|
|
||||||
// pvk, err := configfile.LoadPrivateKey()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// devices, err := apiclient.GetDevices(cc.DeviceId, pvk)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return json.NewEncoder(os.Stdout).Encode(devices)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +1,84 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/AYM1607/ccclip/internal/configfile"
|
"github.com/AYM1607/ccclip/internal/configfile"
|
||||||
|
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getClipboard() (string, error) {
|
||||||
|
cc, err := configfile.EnsureAndGet()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc.DeviceId == "" {
|
||||||
|
return "", errors.New("you must log in and register your device")
|
||||||
|
}
|
||||||
|
pvk, err := configfile.LoadPrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not load this device's private key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
plain, err := apiclient.GetClipboard(cc.DeviceId, pvk)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not set clipboard: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return plain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setClipboard(clip []byte) error {
|
||||||
|
cc, err := configfile.EnsureAndGet()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cc.DeviceId == "" {
|
||||||
|
return errors.New("you must log in and register your device")
|
||||||
|
}
|
||||||
|
pvk, err := configfile.LoadPrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not load this device's private key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = apiclient.SetClipboard(clip, cc.DeviceId, pvk)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not set clipboard: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// rootCmd represents the base command when called without any subcommands
|
// rootCmd represents the base command when called without any subcommands
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "ccclip",
|
Use: "ccclip",
|
||||||
Short: "copy strings to and from your end to end encrypted cloud clipboard",
|
Short: "copy strings to and from your end to end encrypted cloud clipboard",
|
||||||
Long: `copy strings to and from your end to end encrypted cloud clipboard`,
|
Long: `copy strings to and from your end to end encrypted cloud clipboard`,
|
||||||
// Uncomment the following line if your bare application
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
// has an action associated with it:
|
if isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) {
|
||||||
// Run: func(cmd *cobra.Command, args []string) { },
|
// Nothing piped through stdin. Reading clipboard.
|
||||||
|
clip, err := getClipboard()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = os.Stdout.Write([]byte(clip))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clip, err := io.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return setClipboard(clip)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/AYM1607/ccclip/internal/configfile"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
var clipboard string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(setClipboardCmd)
|
|
||||||
|
|
||||||
setClipboardCmd.Flags().StringVar(&clipboard, "clip", "", "the string to send")
|
|
||||||
setClipboardCmd.MarkFlagRequired("clip")
|
|
||||||
}
|
|
||||||
|
|
||||||
var setClipboardCmd = &cobra.Command{
|
|
||||||
Use: "set-clipboard",
|
|
||||||
Short: "set the given string as the cloud clipboard",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
cc, err := configfile.EnsureAndGet()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cc.DeviceId == "" {
|
|
||||||
return errors.New("you must log in and register your device")
|
|
||||||
}
|
|
||||||
pvk, err := configfile.LoadPrivateKey()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not load this device's private key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = apiclient.SetClipboard(clipboard, cc.DeviceId, pvk)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not set clipboard: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -4,6 +4,7 @@ go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/mattn/go-isatty v0.0.20
|
||||||
github.com/mattn/go-sqlite3 v1.14.18
|
github.com/mattn/go-sqlite3 v1.14.18
|
||||||
github.com/oklog/ulid/v2 v2.1.0
|
github.com/oklog/ulid/v2 v2.1.0
|
||||||
github.com/spf13/cobra v1.8.0
|
github.com/spf13/cobra v1.8.0
|
||||||
|
|
|
||||||
3
go.sum
3
go.sum
|
|
@ -3,6 +3,8 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
|
github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
|
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
|
||||||
|
|
@ -15,6 +17,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ func (c *Client) RegisterDevice(email, password string, devicePublicKey []byte)
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) SetClipboard(plaintext string, deviceId string, pvk *ecdh.PrivateKey) error {
|
func (c *Client) SetClipboard(plaintext []byte, deviceId string, pvk *ecdh.PrivateKey) error {
|
||||||
devices, err := c.getDevices(deviceId, pvk)
|
devices, err := c.getDevices(deviceId, pvk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ import (
|
||||||
"github.com/AYM1607/ccclip/pkg/crypto"
|
"github.com/AYM1607/ccclip/pkg/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
func encryptForAll(plaintext string, pvk *ecdh.PrivateKey, devices []*api.Device) map[string][]byte {
|
func encryptForAll(plaintext []byte, pvk *ecdh.PrivateKey, devices []*api.Device) map[string][]byte {
|
||||||
res := map[string][]byte{}
|
res := map[string][]byte{}
|
||||||
for _, d := range devices {
|
for _, d := range devices {
|
||||||
key := crypto.NewSharedKey(pvk, crypto.PublicKeyFromBytes(d.PublicKey), crypto.SendDirection)
|
key := crypto.NewSharedKey(pvk, crypto.PublicKeyFromBytes(d.PublicKey), crypto.SendDirection)
|
||||||
res[d.ID] = crypto.Encrypt(key, []byte(plaintext))
|
res[d.ID] = crypto.Encrypt(key, plaintext)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue