10000 Use secret token instead of verification token for zoombot by joshblum · Pull Request #327 · keybase/managed-bots · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Use secret token instead of verification token for zoombot #327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Keybase Managed Bots

[![Travis CI](https://travis-ci.com/keybase/managed-bots.svg?branch=master)](https://travis-ci.com/keybase/managed-bots)
[![CI](https://github.com/keybase/managed-bots/actions/workflows/ci.yml/badge.svg)](https://github.com/keybase/managed-bots/actions/workflows/ci.yml)

Home of bots managed by [Keybase](https://keybase.io). All of the managed bots
within this repo can be run independently, each directory contains a readme to
Expand Down
4 changes: 2 additions & 2 deletions gcalbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ order to store account and webhook data.
- By default, bots are unable to read their own messages. For development, it may be useful to disable this safeguard.
You can do this using `--read-self` flag when running the bot.
- The following links are helpful for using the Google Calendar API:
- https://developers.google.com/calendar/quickstart/go
- https://developers.google.com/calendar/v3/reference
- https://developers.google.com/calendar/quickstart/go
- https://developers.google.com/calendar/v3/reference

### Docker

Expand Down
5 changes: 2 additions & 3 deletions meetbot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,11 @@ In order to run the Meet bot, there needs to be a running MySQL database in orde
- By default, bots are unable to read their own messages. For development, it may be useful to disable this safeguard.
You can do this using `--read-self` flag when running the bot.
- The following links are helpful for using the Google Calendar API:
- https://developers.google.com/calendar/quickstart/go
- https://developers.google.com/calendar/create-events
- https://developers.google.com/calendar/quickstart/go
- https://developers.google.com/calendar/create-events

### Docker

There are a few complications running a Keybase chat bot, and it is likely
easiest to deploy using Docker. See https://hub.docker.com/r/keybaseio/client
for our preferred client image to get started.

23 changes: 11 additions & 12 deletions zoombot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ In o 8000 rder to run the Zoom bot, there needs to be a running MySQL database in orde
go install .
```
3. Create an OAuth App on the [Zoom Marketplace](https://marketplace.zoom.us/develop/create). Fill in all of
the necessary details (name, description, etc.). Additionally, set the redirect URL *and* whitelist as
`https://mydomain.com/zoombot/oauth`, add `user:read` and `meeting:write` to the Scopes and set the deauthorization
notification endpoint URL as `https://mydomain.com/zoombot/deauthorize`.
the necessary details (name, description, etc.). Additionally, set the redirect URL _and_ whitelist as
`https://mydomain.com/zoombot/oauth`, add `user:read` and `meeting:write` to the Scopes and set the deauthorization
notification endpoint URL as `https://mydomain.com/zoombot/deauthorize`.
4. The bot sets itself up to serve HTTP requests on `/zoombot`. The HTTP server
runs on port 8080. You can configure nginx or any other reverse proxy
software to route to this port and path.
5. To start the Zoom bot, run a command like this:
```
$GOPATH/bin/zoombot --dsn 'root@/zoombot' --http-prefix https://mydomain.com --client-id '<OAuth client ID>' --client-secret '<OAuth client secret>' --verification-token '<Zoom Verification Token>'
$GOPATH/bin/zoombot --dsn 'root@/zoombot' --http-prefix https://mydomain.com --client-id '<OAuth client ID>' --client-secret '<OAuth client secret>' --secret-token '<Zoom Secret Token>'
```
6. Run `zoombot --help` for more options.

Expand All @@ -41,24 +41,23 @@ notification endpoint URL as `https://mydomain.com/zoombot/deauthorize`.
- By default, bots are unable to read their own messages. For development, it may be useful to disable this safeguard.
You can do this using `--read-self` flag when running the bot.
- You can optionally save your Zoom credentials inside your bot account's private KBFS folder.
To do this, create a `credentials.json` and use the `--kbfs-root` flag to specify the folder that it's in
(example: `--kbfs-root /keybase/private/<YourZoomBot>`). The `credentials.json` file should follow this format:
To do this, create a `credentials.json` and use the `--kbfs-root` flag to specify the folder that it's in
(example: `--kbfs-root /keybase/private/<YourZoomBot>`). The `credentials.json` file should follow this format:
```json
{
"client_id": "your Zoom OAuth client ID here",
"client_secret": "your Zoom OAuth client secret here",
"verification_token": "your Zoom verification token here"
"secret_token": "your Zoom secret token here"
}
```
If you have KBFS running, you can now run the bot without providing the `--client-id`, `--client-secret` and `--verification-token` command line options.
If you have KBFS running, you can now run the bot without providing the `--client-id`, `--client-secret` and `--secret-token` command line options.
- The following links are helpful for using the Zoom API:
- https://marketplace.zoom.us/docs/guides/getting-started/app-types/create-oauth-app
- https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate
- https://marketplace.zoom.us/docs/guides/authorization/deauthorization
- https://marketplace.zoom.us/docs/guides/getting-started/app-types/create-oauth-app
- https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate
- https://marketplace.zoom.us/docs/guides/authorization/deauthorization

### Docker

There are a few complications running a Keybase chat bot, and it is likely
easiest to deploy using Docker. See https://hub.docker.com/r/keybaseio/client
for our preferred client image to get started.

35 changes: 19 additions & 16 deletions zoombot/SUPPORT.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
<!-- Hosted at https://zoombot.keybase.pub/support -->
<!-- Hosted at https://zoombot.keybase.pub/support -->

## Installation
* Step by step guide
1. Install Keybase (https://keybase.io/download)
2. Add the Keybase Zoom Bot to your teams and conversations through the following steps:
1. Navigate to the conversation you wish to install Zoom Bot for
2. Click the ‘Chat info & sessions’ button (the icon is an i in a circle) in the top right corner
3. Select the ‘Bots’ tab
4. Scroll down to the entry that says ‘Zoom Bot’ and click the plus. Keybase will guide you through installing the bot
* Uninstalling or deauthorizing the Keybase Zoom Bot from your Zoom Account
* Navigate to https://marketplace.zoom.us/user/installed and click on the “Uninstall” button next to the Keybase integration

- Step by step guide
1. Install Keybase (https://keybase.io/download)
2. Add the Keybase Zoom Bot to your teams and conversations through the following steps:
1. Navigate to the conversation you wish to install Zoom Bot for
2. Click the ‘Chat info & sessions’ button (the icon is an i in a circle) in the top right corner
3. Select the ‘Bots’ tab
4. Scroll down to the entry that says ‘Zoom Bot’ and click the plus. Keybase will guide you through installing the bot
- Uninstalling or deauthorizing the Keybase Zoom Bot from your Zoom Account
- Navigate to https://marketplace.zoom.us/user/installed and click on the “Uninstall” button next to the Keybase integration

## Usage
* `!zoom`: Create a new Zoom meeting
* To use the bot, type `!zoom` in conversations that the Keybase Zoom Bot has been added to.

- `!zoom`: Create a new Zoom meeting
- To use the bot, type `!zoom` in conversations that the Keybase Zoom Bot has been added to.
If you haven’t used the bot before, it will direct message you in order to authenticate with Zoom.
Otherwise, the bot will broadcast a Zoom Instant Meeting link on your behalf to the conversation that you sent
the command into

## Contact Support
* Use the `!zoombot feedback <feedback here>` to provide feedback and questions.
* Report issues here: https://github.com/keybase/managed-bots/issues
* Join @keybasefriends to discuss with the community https://keybase.io/team/keybasefriends
* In app going to `Settings > Feedback` to submit bugs or `keybase log send` from the command line.

- Use the `!zoombot feedback <feedback here>` to provide feedback and questions.
- Report issues here: https://github.com/keybase/managed-bots/issues
- Join @keybasefriends to discuss with the community https://keybase.io/team/keybasefriends
- In app going to `Settings > Feedback` to submit bugs or `keybase log send` from the command line.
18 changes: 9 additions & 9 deletions zoombot/main.go
9E81
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Options struct {
HTTPPrefix string
OAuthClientID string
OAuthClientSecret string
VerificationToken string
SecretToken string
}

func NewOptions() *Options {
Expand Down Expand Up @@ -71,11 +71,11 @@ func (s *BotServer) makeAdvertisement() kbchat.Advertisement {

func (s *BotServer) getCredentials() (credentials *zoombot.Credentials, err error) {
defer s.Trace(&err, "getCredentials")()
if s.opts.OAuthClientID != "" && s.opts.OAuthClientSecret != "" && s.opts.VerificationToken != "" {
if s.opts.OAuthClientID != "" && s.opts.OAuthClientSecret != "" && s.opts.SecretToken != "" {
credentials = &zoombot.Credentials{
ClientID: s.opts.OAuthClientID,
ClientSecret: s.opts.OAuthClientSecret,
VerificationToken: s.opts.VerificationToken,
ClientID: s.opts.OAuthClientID,
ClientSecret: s.opts.OAuthClientSecret,
SecretToken: s.opts.SecretToken,
}
} else {
if len(s.opts.KBFSRoot) == 0 {
Expand All @@ -96,9 +96,9 @@ func (s *BotServer) getCredentials() (credentials *zoombot.Credentials, err erro
}
}

if len(credentials.ClientID) == 0 || len(credentials.ClientSecret) == 0 || len(credentials.VerificationToken) == 0 {
return nil, fmt.Errorf("must provide a clientID (len: %d), clientSecret (len: %d) and verificationToken (len: %d)",
len(credentials.ClientID), len(credentials.ClientSecret), len(credentials.VerificationToken))
if len(credentials.ClientID) == 0 || len(credentials.ClientSecret) == 0 || len(credentials.SecretToken) == 0 {
return nil, fmt.Errorf("must provide a clientID (len: %d), clientSecret (len: %d) and secretToken (len: %d)",
len(credentials.ClientID), len(credentials.ClientSecret), len(credentials.SecretToken))
}

return credentials, nil
Expand Down Expand Up @@ -170,7 +170,7 @@ func mainInner() int {
fs.StringVar(&opts.HTTPPrefix, "http-prefix", os.Getenv("BOT_HTTP_PREFIX"), "address of bots HTTP server for webhooks")
fs.StringVar(&opts.OAuthClientID, "client-id", os.Getenv("BOT_OAUTH_CLIENT_ID"), "Zoom OAuth2 client ID")
fs.StringVar(&opts.OAuthClientSecret, "client-secret", os.Getenv("BOT_OAUTH_CLIENT_SECRET"), "Zoom OAuth2 client secret")
fs.StringVar(&opts.VerificationToken, "verification-token", os.Getenv("BOT_VERIFICATION_TOKEN"), "Zoom verification token")
fs.StringVar(&opts.SecretToken, "secret-token", os.Getenv("BOT_SECRET_TOKEN"), "Zoom secret token")
if err := opts.Parse(fs, os.Args); err != nil {
fmt.Printf("Unable to parse options: %v\n", err)
return 3
Expand Down
45 changes: 38 additions & 7 deletions zoombot/zoombot/http.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package zoombot

import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"

"golang.org/x/oauth2"
Expand Down Expand Up @@ -38,19 +43,45 @@ func (h *HTTPSrv) healthCheckHandler(w http.ResponseWriter, _ *http.Request) {
fmt.Fprintf(w, "OK")
}

// see https://developers.zoom.us/docs/api/webhooks/#verify-with-zooms-header
func (h *HTTPSrv) validateWebhookMessage(bodyBytes []byte, r *http.Request) (err error) {
requestTimestamp := r.Header.Get("x-zm-request-timestamp")
message := fmt.Sprintf("v0:%s:%s", requestTimestamp, bodyBytes)
hash := hmac.New(sha256.New, []byte(h.credentials.SecretToken))
_, err = hash.Write([]byte(message))
if err != nil {
return err
}
actualSig := fmt.Sprintf("v0=%s", hex.EncodeToString(hash.Sum(nil)))
givenSig := r.Header.Get("x-zm-signature")
if givenSig != actualSig {
return fmt.Errorf("invalid signature %s!=%s", actualSig, givenSig)
}
return nil
}

func (h *HTTPSrv) zoomDeauthorize(w http.ResponseWriter, r *http.Request) {
var deauthorizationRequest DeauthorizationRequest
err := json.NewDecoder(r.Body).Decode(&deauthorizationRequest)
bodyBytes, err := io.ReadAll(r.Body)
defer r.Body.Close()
if err != nil {
h.Errorf("zoomDeauthorize: parsing error: %s", err)
h.Errorf("zoomDeauthorize: unable to read body: %s", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

verificationToken := r.Header.Get("Authorization")
if verificationToken != h.credentials.VerificationToken {
h.Errorf("zoomDeauthorize: wrong verificationToken: %s", verificationToken)
http.Error(w, "wrong verificationToken", http.StatusBadRequest)
err = h.validateWebhookMessage(bodyBytes, r)
if err != nil {
h.Errorf("zoomDeauthorize: invalid signature: %s", err)
http.Error(w, "invalid signature", http.StatusBadRequest)
return
}

reader := bytes.NewReader(bodyBytes)
var deauthorizationRequest DeauthorizationRequest
err = json.NewDecoder(reader).Decode(&deauthorizationRequest)
if err != nil {
h.Errorf("zoomDeauthorize: parsing error: %s", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

Expand Down
6 changes: 3 additions & 3 deletions zoombot/zoombot/type.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package zoombot

type Credentials struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
VerificationToken string `json:"verification_token"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
SecretToken string `json:"secret_token"`
}
0