diff --git a/cmd/signaldctl/cmd/message/send/send-message.go b/cmd/signaldctl/cmd/message/send/send-message.go index 81b4f44..4e99598 100644 --- a/cmd/signaldctl/cmd/message/send/send-message.go +++ b/cmd/signaldctl/cmd/message/send/send-message.go @@ -18,9 +18,11 @@ package send import ( "encoding/json" "fmt" + "io" "io/ioutil" "log" "os" + "os/exec" "path/filepath" "strings" @@ -30,15 +32,20 @@ import ( "gitlab.com/signald/signald-go/cmd/signaldctl/common" "gitlab.com/signald/signald-go/cmd/signaldctl/config" - "gitlab.com/signald/signald-go/signald/client-protocol/v1" + v1 "gitlab.com/signald/signald-go/signald/client-protocol/v1" +) + +const ( + CAPTCHA_HELPER = "signal-captcha-helper" ) var ( - account string - toAddress *v1.JsonAddress - toGroup string - attachments []string - message string + account string + toAddress *v1.JsonAddress + toGroup string + attachments []string + message string + captchaHelper bool SendMessageCmd = &cobra.Command{ Use: "send {group id | phone number} [message]", @@ -97,6 +104,48 @@ var ( if err != nil { log.Fatal("error sending request to signald: ", err) } + + resends := []*v1.JsonAddress{} + + for _, result := range resp.Results { + if result.ProofRequiredFailure != nil { + if captchaHelper { + err = runCaptchaHelper(result.ProofRequiredFailure.Token) + if err != nil { + log.Println("error running captcha helper: ", err) + } + resends = append(resends, result.Address) + } + } + } + + if len(resends) > 0 { + resendReq := v1.SendRequest{ + Username: req.Username, + MessageBody: req.MessageBody, + Attachments: req.Attachments, + RecipientGroupID: req.RecipientGroupID, + Members: resends, + Timestamp: resp.Timestamp, + } + resendResponse, err := resendReq.Submit(common.Signald) + if err != nil { + log.Println("error resending messages: ", err) + } else { + for i, originalResult := range resp.Results { + if originalResult.ProofRequiredFailure == nil { + continue + } + + for _, result := range resendResponse.Results { + if result.Address.UUID == originalResult.Address.UUID { + resp.Results[i] = result + } + } + } + } + } + switch common.OutputFormat { case common.OutputFormatJSON: err := json.NewEncoder(os.Stdout).Encode(resp) @@ -148,7 +197,55 @@ var ( } ) +func runCaptchaHelper(challenge string) error { + if !captchaHelper { + return nil + } + + _, err := exec.LookPath(CAPTCHA_HELPER) + if err != nil { + return err + } + + cmd := exec.Command(CAPTCHA_HELPER, "--challenge") + + stdout, err := cmd.StdoutPipe() + if err != nil { + return err + } + + err = cmd.Start() + if err != nil { + return err + } + + captchaToken := new(strings.Builder) + _, err = io.Copy(captchaToken, stdout) + if err != nil { + return err + } + + err = cmd.Wait() + if err != nil { + return err + } + + req := v1.SubmitChallengeRequest{ + Account: account, + CaptchaToken: captchaToken.String(), + Challenge: challenge, + } + + err = req.Submit(common.Signald) + if err != nil { + return err + } + + return nil +} + func init() { SendMessageCmd.Flags().StringVarP(&account, "account", "a", "", "local account to use") + SendMessageCmd.Flags().BoolVarP(&captchaHelper, "captcha-helper", "c", false, "Invoke signal-captcha-helper and process the response when a push challenge response appears. After completing the challenge, the message will be redelivered to the failed recipient") SendMessageCmd.Flags().StringSliceVarP(&attachments, "attachment", "A", []string{}, "attach a file to your outbound message. may be specified multiple times.") }