// sendError is a helper method used to write out error responses. Any message // passed to it will be wrapped in an error response and written out. func sendError(w http.ResponseWriter, msg string) { e := &api.ApiError{ Error: msg, } log.Debug("Client error sent: " + msg) w.WriteHeader(http.StatusBadRequest) writeResponse(&w, e) }
// Validate uses the token and request time of the request to calculate a HMAC // signature for the request. This is then compared to the one provided with the // message to validate its authenticity. func (request *ApiRequest) Validate(secret string) bool { t, err := time.Parse(time.RFC3339, request.RequestTime) if err != nil { log.Debug("Could not parse requestTime") return false } if time.Since(t) > 30*time.Minute { log.Debug("Time is too far out of sync") return false } key := []byte(secret) sig := request.Token + request.RequestTime data := []byte(sig) signature, err := base64.StdEncoding.DecodeString(request.Signature) mac := hmac.New(sha256.New, key) mac.Write(data) expectedMAC := mac.Sum(nil) return hmac.Equal(signature, expectedMAC) }
// Put sends a message to a series of mailboxes. An array of mailboxes can be // provided, as well as a pattern using '*' as wildcards. The message will by // sent to all matching mailboxes. func (client *Client) Put(mbxs []string, pattern string, msg string, deploymentName string, asset string) (*api.PutMessageResponse, error) { md5, _ := client.hashFile(asset) if asset != "" { exists, err := client.CheckRemoteFile(md5) if err != nil { return nil, err } if exists == true { log.Info("File exists on server, skipping upload") } else { _, err := client.Upload(asset) if err != nil { log.Debug(err.Error()) return nil, errors.New("Could not upload asset") } } } request := api.PutMessageRequest{ Mailboxes: mbxs, Body: msg, Pattern: pattern, DeploymentName: deploymentName, Asset: md5, } request.Sign(client.AccessKeyName, client.AccessKey) var response api.PutMessageResponse err := client.request("put", request, &response) if err != nil { return nil, err } if !response.Validate(client.AccessKey) { return nil, errors.New("Server responded with an invalid signature") } return &response, nil }
// getDeploymentInfo returns the information about a deployment. func getDeploymentInfo(depId string, consolidate bool) { client, _ := ClientFromConfig() stats, err := client.PollDeployment(depId, func(stats *api.DeploymentStats) bool { return false }) if err != nil { log.Debug(err.Error()) log.Error("Could not get deployment results") return } log.Info("") log.Alert(depId) log.Info("") log.Infof("Total messages: %d", stats.MessageCount) log.Infof("Pending messages: %d", stats.PendingCount) log.Infof("Total responses: %d", stats.ResponseCount) if len(stats.Responses) > 0 { log.Alert("\nResponses:") } stats.Responses.Sort() displayResponses(stats.Responses, consolidate) log.Info("") }
"conduit/log" "github.com/spf13/cobra" "postmaster/mailbox" ) // acessListCmd represents the acessList command var accessListCmd = &cobra.Command{ Use: "list", Short: "List all administrative access keys", Long: `Display a list of all administrative access keys that have been generated using 'conduit server access'. The server must be stopped when running this command.`, Run: func(cmd *cobra.Command, args []string) { mailbox.OpenDB() keys, err := mailbox.AdminKeys() if err != nil { log.Debug(err.Error()) log.Fatal("Could not list keys") } log.Alert("Access keys:") for _, k := range keys { log.Info(k.Name) } mailbox.CloseDB() }, } func init() { accessCmd.AddCommand(accessListCmd) }
func runClient(noLoop bool) { viper.SetDefault("script_timeout", 300) log.LogFile = true if viper.GetBool("master.enabled") { log.Info("Launching master server") go runProxy() } log.Info("Waiting for messages...") client, _ := ClientFromConfig() if viper.IsSet("master.host") { client.UseProxy = true client.ProxyAddress = "http://" + viper.GetString("master.host") } var persistantScripts = []*engine.ScriptEngine{} if viper.IsSet("agents") { engine.Agents = viper.GetStringMapString("agents") engine.AgentAccessKey = viper.GetString("access_key") } // Begin polling cycle for { time.Sleep(time.Duration(rand.Intn(1000)+2000) * time.Millisecond) resp, err := client.Get() // If an error is returned by the client we will begin an exponential back // off in retrying. The backoff caps out at 15 retries. if err != nil { log.Error("Error getting messages: " + err.Error()) if errorCount < 15 { errorCount++ } expBackoff := int(math.Pow(float64(errorCount), 2)) displacement := rand.Intn(errorCount + 1) sleepTime := expBackoff + displacement time.Sleep(time.Duration(sleepTime) * time.Second) continue } // A response was received but it might be an empty response from the // server timing out the long poll. errorCount = 0 if resp.Body != "" { log.Infof("Script receieved (%s)", resp.Message) eng := engine.New() eng.Constant("DEPLOYMENT_ID", resp.Deployment) eng.Constant("SCRIPT_ID", resp.Message) persistant, _ := eng.GetVar("$persistant", resp.Body) if p, ok := persistant.(bool); ok { if p { persistantScripts = append(persistantScripts, eng) } } if resp.Asset != "" { assetPath, err := client.DownloadAsset(resp.Asset) if err != nil { client.Respond(resp.Message, "Could not download asset", true) log.Error("Could not download asset") _, err = client.Delete(resp.Message) continue } else { log.Infof("Downloaded asset to %s", assetPath) } eng.SetAsset(assetPath) } executionStartTime := time.Now() errChan := make(chan string, 1) timeoutSeconds := viper.GetInt("script_timeout") go func() { err = eng.Execute(resp.Body) if err != nil { errChan <- err.Error() } else { errChan <- "" } }() select { case e := <-errChan: if e != "" { err = errors.New(e) } case <-time.After(time.Second * time.Duration(timeoutSeconds)): log.Warn("Timing out script") err = errors.New("Scirpt timeed out") } executionTime := time.Since(executionStartTime) log.Infof("Script executed in %s", executionTime) if err != nil { log.Error("Error executing script " + resp.Message) log.Debug(err.Error()) client.Respond(resp.Message, err.Error(), true) } _, err = client.Delete(resp.Message) if err != nil { log.Debug(err.Error()) log.Error("Could not confirm script.") } else { log.Debug("Script confirmed: " + resp.Message) } } if noLoop == true { break } } }