Created
September 9, 2021 16:27
-
-
Save dmulder/129a386abfe43d44ceffaaae188ddebd to your computer and use it in GitHub Desktop.
Slack autotoken modified to simply load a browser for authentication (for complicated auth situations). Taken from https://github.com/insomniacslk/irc-slack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// autotoken retrieves a Slack token and cookie using your Slack team | |
// credentials. | |
package main | |
import ( | |
"context" | |
"encoding/json" | |
"fmt" | |
"log" | |
"os" | |
"strings" | |
"time" | |
"github.com/chromedp/cdproto/network" | |
"github.com/chromedp/cdproto/runtime" | |
"github.com/chromedp/chromedp" | |
"github.com/spf13/pflag" | |
) | |
var ( | |
flagDebug = pflag.BoolP("debug", "d", false, "Enable debug log") | |
flagShowBrowser = pflag.BoolP("show-browser", "b", true, "show browser, useful for debugging") | |
flagMFA = pflag.StringP("mfa", "m", "", "Provide a multi-factor authentication token (necessary if MFA is enabled on your account)") | |
flagWaitGDPRNotice = pflag.BoolP("gdpr", "g", false, "Wait for Slack's GDPR notice pop-up before inserting username and password. Use this to work around login failures") | |
flagTimeout = pflag.UintP("timeout", "t", 120, "Timeout in seconds") | |
) | |
func main() { | |
usage := func() { | |
fmt.Fprintf(os.Stderr, "autotoken: log into slack team and get token and cookie.\n\n") | |
fmt.Fprintf(os.Stderr, "Usage: %s [-d] teamname[.slack.com]\n\n", os.Args[0]) | |
pflag.PrintDefaults() | |
os.Exit(1) | |
} | |
pflag.Usage = usage | |
pflag.Parse() | |
if len(pflag.Args()) < 1 { | |
usage() | |
} | |
team := pflag.Arg(0) | |
email := "" | |
var password string | |
password = "" | |
timeout := time.Duration(*flagTimeout) * time.Second | |
token, cookie, err := fetchCredentials(context.TODO(), team, email, password, *flagMFA, *flagWaitGDPRNotice, timeout, *flagShowBrowser, *flagDebug) | |
if err != nil { | |
log.Fatalf("Failed to fetch credentials for team `%s`: %v", team, err) | |
} | |
fmt.Printf("%s|%s\n", token, cookie) | |
} | |
// fetchCredentials fetches Slack token and cookie for a given team. | |
func fetchCredentials(ctx context.Context, team, email, password, mfa string, waitGDPRNotice bool, timeout time.Duration, showBrowser, doDebug bool) (string, string, error) { | |
if !strings.HasSuffix(team, ".slack.com") { | |
team += ".slack.com" | |
} | |
teamURL := "https://" + team | |
var cancel func() | |
ctx, cancel = context.WithTimeout(ctx, timeout) | |
defer cancel() | |
// show browser | |
if showBrowser { | |
ctx, cancel = chromedp.NewExecAllocator(ctx, chromedp.NoFirstRun, chromedp.NoDefaultBrowserCheck) | |
defer cancel() | |
} | |
var opts []chromedp.ContextOption | |
if doDebug { | |
opts = append(opts, chromedp.WithDebugf(log.Printf)) | |
} | |
ctx, cancel = chromedp.NewContext(ctx, opts...) | |
defer cancel() | |
fmt.Fprintf(os.Stderr, "Fetching token and cookie for %s on %s\n", email, team) | |
// run chromedp tasks | |
return submit(ctx, teamURL, `//input[@id="email"]`, email, `//input[@id="password"]`, password, mfa, waitGDPRNotice) | |
} | |
// submit authenticates through Slack and returns token and cookie, or an error. | |
func submit(ctx context.Context, urlstr, selEmail, email, selPassword, password, mfa string, waitGDPRNotice bool) (string, string, error) { | |
tasks := chromedp.Tasks{ | |
chromedp.Navigate(urlstr), | |
} | |
if err := chromedp.Run(ctx, tasks); err != nil { | |
return "", "", fmt.Errorf("failed to send credentials: %w", err) | |
} | |
return extractTokenAndCookie(ctx) | |
} | |
// extractTokenAndCookie extracts Slack token and cookie from an existing | |
// context. | |
func extractTokenAndCookie(ctx context.Context) (string, string, error) { | |
var token, cookie string | |
tasks := chromedp.Tasks{ | |
chromedp.WaitVisible(".p-workspace__primary_view_contents"), | |
chromedp.ActionFunc(func(ctx context.Context) error { | |
v, exp, err := runtime.Evaluate(`q=JSON.parse(localStorage.localConfig_v2)["teams"]; q[Object.keys(q)[0]]["token"]`).Do(ctx) | |
if err != nil { | |
return err | |
} | |
if exp != nil { | |
return exp | |
} | |
if err := json.Unmarshal(v.Value, &token); err != nil { | |
return fmt.Errorf("failed to unmarshal token: %v", err) | |
} | |
return nil | |
}), | |
chromedp.ActionFunc(func(ctx context.Context) error { | |
cookies, err := network.GetAllCookies().Do(ctx) | |
if err != nil { | |
return err | |
} | |
for _, c := range cookies { | |
if c.Name == "d" { | |
cookie = fmt.Sprintf("d=%s;", c.Value) | |
} | |
} | |
return nil | |
}), | |
} | |
if err := chromedp.Run(ctx, tasks); err != nil { | |
return "", "", err | |
} | |
return token, cookie, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just run
go mod init
thengo build
to make the autotoken executable.