Module: Brainiac::Plugins::Zoho

Defined in:
lib/brainiac/plugins/zoho.rb,
lib/brainiac/plugins/zoho/cli.rb,
lib/brainiac/plugins/zoho/config.rb,
lib/brainiac/plugins/zoho/triage.rb,
lib/brainiac/plugins/zoho/handler.rb,
lib/brainiac/plugins/zoho/version.rb,
lib/brainiac/plugins/zoho/mail_api.rb,
lib/brainiac/plugins/zoho/metadata.rb

Defined Under Namespace

Modules: Cli, Config, Handler, MailApi, Triage

Constant Summary collapse

ZOHO_AUTH_SCOPES =
"ZohoMail.messages.READ,ZohoMail.accounts.READ,ZohoMail.folders.READ"
VERSION =
"0.0.2"

Class Method Summary collapse

Class Method Details

.cli(args) ⇒ Object

Plugin CLI entry points



83
84
85
# File 'lib/brainiac/plugins/zoho/cli.rb', line 83

def self.cli(args)
  Cli.run(args)
end

.completionsObject



87
88
89
# File 'lib/brainiac/plugins/zoho/cli.rb', line 87

def self.completions
  %w[setup config auth]
end

.configured?Boolean

Returns true if Zoho config file exists.

Returns:

  • (Boolean)


12
13
14
15
16
17
# File 'lib/brainiac/plugins/zoho/metadata.rb', line 12

def self.configured?
  config_file = File.join(ENV.fetch("BRAINIAC_DIR", File.join(Dir.home, ".brainiac")), "zoho.json")
  File.exist?(config_file)
rescue StandardError
  false
end

.help_textObject

Help text shown in brainiac help when the plugin is installed.



20
21
22
# File 'lib/brainiac/plugins/zoho/metadata.rb', line 20

def self.help_text
  "    brainiac zoho <command>       Manage Zoho Mail webhooks (setup, config, auth)"
end

.post_install(brainiac_dir) ⇒ Object

Called after brainiac install zoho — creates config from template.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/brainiac/plugins/zoho.rb', line 30

def post_install(brainiac_dir)
  config_file = File.join(brainiac_dir, "zoho.json")
  return if File.exist?(config_file)

  template = File.expand_path("../../templates/zoho.json.example", __dir__)
  if File.exist?(template)
    FileUtils.cp(template, config_file)
  else
    default_config = {
      "hook_secret" => nil,
      "default_notify_target" => "",
      "notify_channel" => "discord",
      "notify_as" => "merlin",
      "rules" => [],
      "fallback" => { "enabled" => true, "label" => "Unmatched Email", "emoji" => "📬" }
    }
    File.write(config_file, JSON.pretty_generate(default_config))
  end
end

.register(app) ⇒ Object

Called by Brainiac plugin system during server startup.

Parameters:

  • app (Sinatra::Application)

    The running Brainiac server



23
24
25
26
27
# File 'lib/brainiac/plugins/zoho.rb', line 23

def register(app)
  Config.load!
  setup_routes(app)
  LOG.info "[Zoho] Plugin registered (webhook: /zoho)"
end

.verify_signature!(request, payload_body) ⇒ Object

Verify the X-Hook-Signature header (base64 HMAC-SHA256 of the raw body).



150
151
152
153
154
155
156
157
158
159
# File 'lib/brainiac/plugins/zoho.rb', line 150

def self.verify_signature!(request, payload_body)
  signature = request.env["HTTP_X_HOOK_SIGNATURE"]
  return unless signature

  secret = Config.hook_secret
  halt 500, { error: "No hook_secret configured — waiting for initial Zoho handshake" }.to_json unless secret

  computed = Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", secret, payload_body))
  halt 403, { error: "Invalid Zoho signature" }.to_json unless Rack::Utils.secure_compare(signature, computed)
end