slackauth

package module
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2024 License: MIT Imports: 18 Imported by: 5

README

= Slackauth
:hide-uri-scheme:

Slackauth is an experimental Slack authentication library using
https://github.com/go-rod/rod[Rod] library.

The advantage over the Playwright is that rod utilises 
https://chromedevtools.github.io/devtools-protocol/[CDP], which is faster
and does not require nodejs.  The drawback is that it can't use Firefox.

https://pkg.go.dev/github.com/rusq/slackauth[Go package documentation]

== Types of login

The library implements two types of Login:

1. Manual (interactive)
2. Headless (automatic)

=== Manual (interactive)

In the Manual mode, the browser opens on the address of the Slack
workspace, and user needs to follow the usual authentication flow, it could be
a Email/Password, SSO, etc., except Google Auth.  Google has bot detection
that detects the puppet browser (read below)

Call the `client.Manual` function to start the Manual login.  It will
block until the timeout expires or the user does something, i.e. logs in or
closes the page/browser.

The library detects if the user closes the tab with Slack website or the
browser, in this case the function returns an error.  It doesn't track the
website that user is on, so user can navigate away and browse the web, if they
decide so, until the timeout destroys the browser.

==== Google Auth

Google Authentication is a special case, as it detects the automated browser.
To authenticate with Google Auth, one needs to use the "WithForceUser" when
initialising the client with "New", i.e.:

[source,go]
---
cl, err := slackauth.New("my_workspace", slackauth.WithForceUser)
// check error
---

The user browser must be closed completely (the browser process should not be
started) before using this option, otherwise ROD will fail to establish the
connection to the browser, and return an error.

When "cl.Manual()" is called, it will start up the Chrome-family browser
installed on the system and offer the user to login.  If the browser already
logged in to the requested workspace, it will hijack the cookies immediately
after the slack page loads without any required user interaction.

==== Example

[source,go]
----
func browserLogin(ctx context.Context) {
	const workspace = "some workspace"
	ctx, cancel := context.WithTimeoutCause(ctx, 180*time.Second, errors.New("user too slow"))
	defer cancel()

	cl, err := slackauth.New(workspace, slackauth.WithNoConsentPrompt())
	if err != nil {
		log.Fatal(err)
	}
	defer cl.Close()

	token, cookies, err := cl.Manual(ctx)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(token)
	fmt.Println(cookies)
}
----

=== Headless

In the Headless mode, the browser is not visible to the user, and the
authentication flow is automated.  The user needs to provide the workspace,
email and password, and the library will do the rest.

Call the `slackauth.Headless` function to start the Headless login.  It will
block until login succeeds or fails.

There's a special case when Slack does not recognise the browser and asks the
user to enter the confirmation code that was sent on the user's email.  In
this case, Headless calls the provided interactive challenge function (see the
`WithChallengeFunc` option) and waits for the user to enter the code.  After
the user enters the code, it will be passed to the page and the login process
will continue.

There's the fallback challenge function, but it's simple and ugly, so you're
encouraged to provide your own beautiful one.

Overall, headless login looks nicer, but more fragile - it will start failing
should Slack decide to change the login elements.

==== Example

[source,go]
----
func autoLogin(ctx context.Context) {
	ctx, cancel := context.WithTimeoutCause(ctx, 180*time.Second, errors.New("user too slow"))
	defer cancel()

	workspace := envOrScan("AUTH_WORKSPACE", "Enter workspace: ")
	username := envOrScan("EMAIL", "Enter email: ")
	password := envOrScan("PASSWORD", "Enter password: ")

	cl, err := slackauth.New(ctx, workspace, slackauth.WithDebug(), slackauth.WithNoConsentPrompt())
	if err != nil {
		log.Fatal(err)
	}
	defer cl.Close()

	token, cookies, err := cl.Headless(ctx, username, password)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(token)
	fmt.Println(cookies)
}

func envOrScan(env, prompt string) string {
	v := os.Getenv(env)
	if v != "" {
		return v
	}
	for v == "" {
		fmt.Print(prompt)
		fmt.Scanln(&v)
	}
	return v
}
----

== References
- https://pkg.go.dev/github.com/rusq/slackauth[slackauth package documentation]
- https://go-rod.github.io/[Rod documentation]
- https://chromedevtools.github.io/devtools-protocol/1-3/[Chrome DevTools Protocol (stable, 1.3)]

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidCredentials indicates that the credentials were invalid.
	ErrInvalidCredentials = errors.New("invalid credentials")
	// ErrLoginError indicates that some error of unknown nature occurred
	// during login.
	ErrLoginError = errors.New("slack reported an error during login")
	// ErrWorkspaceNotFound indicates that the workspace name was invalid.
	ErrWorkspaceNotFound = errors.New("workspace not found")
	// ErrInvalidChallengeCode indicates that the challenge code was invalid.
	ErrInvalidChallengeCode = errors.New("invalid challenge code")
)
View Source
var Browser = Manual

Browser is a function that initiates a login flow in a browser.

Deprecated: Use Client.Manual instead.

View Source
var (
	DefaultUserAgent = UserAgent(defaultWebkitVersion, defaultChromeVersion, "")
)
View Source
var ErrNoBrowsers = fmt.Errorf("no browsers found")

Functions

func Headless deprecated

func Headless(ctx context.Context, workspace, email, password string, opt ...Option) (string, []*http.Cookie, error)

Headless logs the user in headlessly, without opening the browser UI. It is only suitable for user/email login method, as it does not require any additional user interaction.

Deprecated: Use Client.Headless instead.

func Manual deprecated added in v0.3.0

func Manual(ctx context.Context, workspace string, opt ...Option) (string, []*http.Cookie, error)

Browser initiates a login flow in a browser (manual login).

Deprecated: Use Client.Manual instead.

func RemoveBrowser added in v0.5.0

func RemoveBrowser() error

RemveBundled removes the bundled browser from the system.

func SimpleChallengeFn added in v0.0.6

func SimpleChallengeFn(email string) (int, error)

SimpleChallengeFn is a simple challenge function that reads a single integer from stdin. It is used as a default challenge function when none is provided.

func UserAgent added in v0.3.0

func UserAgent(webkitVer, chromeVer, os string) string

UserAgent returns a user agent string with the given WebKit and Chrome versions, and the OS. If any of the versions are empty, the default versions are used. If the OS is empty, the OS is determined from the runtime.GOOS.

Types

type Client added in v0.3.0

type Client struct {
	// contains filtered or unexported fields
}

Client is a Slackauth client. Zero value is not usable, use New to create a new client.

func New added in v0.3.0

func New(workspace string, opt ...Option) (*Client, error)

New creates a new Slackauth client.

func (*Client) Close added in v0.3.0

func (c *Client) Close() error

Close closes the client and cleans up resources.

func (*Client) Headless added in v0.3.0

func (c *Client) Headless(ctx context.Context, email, password string, callback ...func()) (string, []*http.Cookie, error)

Headless logs the user in headlessly, without opening the browser UI. It is only suitable for user/email login method, as it does not require any additional user interaction, except the challenge code. Optional callback function can be provided, it will be called if the challenge code is required.

func (*Client) Manual added in v0.3.0

func (c *Client) Manual(ctx context.Context) (string, []*http.Cookie, error)

Manual initiates a login flow in a browser (manual login).

type ErrBadWorkspace

type ErrBadWorkspace struct {
	Name string
}

ErrBadWorkspace is returned when the workspace name is invalid.

func (ErrBadWorkspace) Error

func (e ErrBadWorkspace) Error() string

type ErrBrowser

type ErrBrowser struct {
	Err      error
	FailedTo string
}

ErrBrowser indicates the error with browser interaction.

func (ErrBrowser) Error

func (e ErrBrowser) Error() string

type LocalBrowser added in v0.5.0

type LocalBrowser struct {
	Name string
	Path string
}

LocalBrowser represents a browser that is installed on the system.

func ListBrowsers added in v0.5.0

func ListBrowsers() ([]LocalBrowser, error)

ListBrowsers returns a list of browsers that are installed on the system.

type Logger added in v0.1.1

type Logger interface {
	// Debug logs a debug message.
	Debug(msg string, keyvals ...interface{})
}

Logger is the interface for the logger.

type Option

type Option func(*options)

func WithAutologinTimeout added in v0.3.0

func WithAutologinTimeout(d time.Duration) Option

WithAutoLoginTimeout sets the timeout for the auto-login method. The default is 40 seconds. This is the net time needed for the automation process to complete, it does not include the time needed to start the browser, or navigate to the login page.

func WithBundledBrowser added in v0.4.0

func WithBundledBrowser() Option

WithBundledBrowser forces the client to use the bundled browser.

func WithChallengeFunc added in v0.0.6

func WithChallengeFunc(fn func(email string) (code int, err error)) Option

WithChallengeFunc sets the function that is called when slack does not recognise the browser and challenges the user with a code sent to email. All the function has to do is to accept the user input and return the code.

See SimpleChallengeFn(#SimpleChallengeFn) for an example.

func WithCookie

func WithCookie(cookie ...*http.Cookie) Option

WithCookie adds a cookie to the request.

func WithDebug

func WithDebug(b bool) Option

WithDebug enables debug logging.

func WithForceUser added in v0.4.0

func WithForceUser() Option

WithForceUser forces the client to try to use the user's browser. Using the user's browser can be used to avoid bot-detection mechanisms, as per this rod issue.

func WithLocalBrowser added in v0.5.0

func WithLocalBrowser(path string) Option

func WithLogger added in v0.1.1

func WithLogger(l Logger) Option

WithLogger sets the logger for the client.

func WithNoConsentPrompt

func WithNoConsentPrompt() Option

WithNoConsentPrompt adds a cookie that disables the Cookie Consent banner.

func WithUserAgent added in v0.3.0

func WithUserAgent(ua string) Option

WithUserAgent sets the user agent for the session.

Directories

Path Synopsis
cmd
playground
Command playground is a manual testing tool.
Command playground is a manual testing tool.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL