stash/pkg/scraper/cookies.go

162 lines
4.2 KiB
Go

package scraper
import (
"context"
"fmt"
"math/rand"
"net/http"
"net/http/cookiejar"
"net/url"
"time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"
"golang.org/x/net/publicsuffix"
"github.com/stashapp/stash/pkg/logger"
)
// jar constructs a cookie jar from a configuration
func (c config) jar() (*cookiejar.Jar, error) {
opts := c.DriverOptions
jar, err := cookiejar.New(&cookiejar.Options{
PublicSuffixList: publicsuffix.List,
})
if err != nil {
return nil, err
}
if opts == nil || opts.UseCDP {
return jar, nil
}
for i, ckURL := range opts.Cookies {
url, err := url.Parse(ckURL.CookieURL) // CookieURL must be valid, include schema
if err != nil {
logger.Warnf("skipping cookie [%d] for cookieURL %s: %v", i, ckURL.CookieURL, err)
continue
}
var httpCookies []*http.Cookie
for _, cookie := range ckURL.Cookies {
c := &http.Cookie{
Name: cookie.Name,
Value: getCookieValue(cookie),
Path: cookie.Path,
Domain: cookie.Domain,
}
httpCookies = append(httpCookies, c)
}
jar.SetCookies(url, httpCookies)
if jar.Cookies(url) == nil {
logger.Warnf("setting jar cookies for %s failed", url.String())
}
}
return jar, nil
}
func getCookieValue(cookie *scraperCookies) string {
if cookie.ValueRandom > 0 {
return randomSequence(cookie.ValueRandom)
}
return cookie.Value
}
var characters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
func randomSequence(n int) string {
b := make([]rune, n)
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = characters[rand.Intn(len(characters))]
}
return string(b)
}
// printCookies prints all cookies from the given cookie jar
func printCookies(jar *cookiejar.Jar, scraperConfig config, msg string) {
driverOptions := scraperConfig.DriverOptions
if driverOptions != nil && !driverOptions.UseCDP {
var foundURLs []*url.URL
for _, ckURL := range driverOptions.Cookies { // go through all cookies
url, err := url.Parse(ckURL.CookieURL) // CookieURL must be valid, include schema
if err == nil {
foundURLs = append(foundURLs, url)
}
}
if len(foundURLs) > 0 {
logger.Debugf("%s\n", msg)
printJarCookies(jar, foundURLs)
}
}
}
// print all cookies from the jar of the native http client for given urls
func printJarCookies(jar *cookiejar.Jar, urls []*url.URL) {
for _, url := range urls {
logger.Debugf("Jar cookies for %s", url.String())
for i, cookie := range jar.Cookies(url) {
logger.Debugf("[%d]: Name: \"%s\" Value: \"%s\"", i, cookie.Name, cookie.Value)
}
}
}
// set all cookies listed in the scraper config
func setCDPCookies(driverOptions scraperDriverOptions) chromedp.Tasks {
return chromedp.Tasks{
chromedp.ActionFunc(func(ctx context.Context) error {
// create cookie expiration
expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
for _, ckURL := range driverOptions.Cookies {
for _, cookie := range ckURL.Cookies {
err := network.SetCookie(cookie.Name, getCookieValue(cookie)).
WithExpires(&expr).
WithDomain(cookie.Domain).
WithPath(cookie.Path).
WithHTTPOnly(false).
WithSecure(false).
Do(ctx)
if err != nil {
return fmt.Errorf("could not set chrome cookie %s: %s", cookie.Name, err)
}
}
}
return nil
}),
}
}
// print cookies whose domain is included in the scraper config
func printCDPCookies(driverOptions scraperDriverOptions, msg string) chromedp.Action {
return chromedp.ActionFunc(func(ctx context.Context) error {
chromeCookies, err := network.GetCookies().Do(ctx)
if err != nil {
return err
}
scraperDomains := make(map[string]struct{})
for _, ckURL := range driverOptions.Cookies {
for _, cookie := range ckURL.Cookies {
scraperDomains[cookie.Domain] = struct{}{}
}
}
if len(scraperDomains) > 0 { // only print the cookies if they are listed in the scraper
logger.Debugf("%s\n", msg)
for i, cookie := range chromeCookies {
_, ok := scraperDomains[cookie.Domain]
if ok {
logger.Debugf("[%d]: Name: \"%s\" Value: \"%s\" Domain: \"%s\"", i, cookie.Name, cookie.Value, cookie.Domain)
}
}
}
return nil
})
}