aisk/browsercookies

View on GitHub
firefox.go

Summary

Maintainability
A
45 mins
Test Coverage
package browsercookies

import (
    "database/sql"
    "errors"
    "io"
    "io/ioutil"
    "net/http"
    "net/http/cookiejar"
    "net/url"
    "os"
    "path/filepath"
    "runtime"
    "time"

    "github.com/go-ini/ini"
    _ "github.com/mattn/go-sqlite3"
    "github.com/mitchellh/go-homedir"
    "golang.org/x/net/publicsuffix"
)

// FireFox is the cookie jar which loads all your cookies in FireFox.
type FireFox struct {
    http.CookieJar
}

func (ff *FireFox) parseProfile(profile string) (string, error) {
    cfg, err := ini.Load(profile)
    if err != nil {
        return "", err
    }
    // TODO: return first profile when no default default profile set.
    for _, section := range cfg.Sections() {
        if section.Key("Default").String() != "1" {
            continue
        }
        path := section.Key("Path").String()
        if section.Key("IsRelative").String() == "1" {
            path = filepath.Join(filepath.Dir(profile), path)
        }
        return path, nil
    }

    return "", errors.New("No default Firefox profile found")
}

func (ff *FireFox) findDefaultProfile() (string, error) {
    homedir, err := homedir.Dir()
    if err != nil {
        return "", err
    }
    switch runtime.GOOS {
    case "darwin":
        return filepath.Join(homedir, filepath.FromSlash("Library/Application Support/Firefox/profiles.ini")), nil
    case "linux":
        return filepath.Join(homedir, filepath.FromSlash(".mozilla/firefox/profiles.ini")), nil
    case "win32":
        return filepath.Join(os.Getenv("APPDATA"), filepath.FromSlash("Mozilla/Firefox/profiles.ini")), nil
    }
    return "", errors.New("Unsupported operating system: " + runtime.GOOS)
}

func (ff *FireFox) findCookieFiles() (string, error) {
    profile, err := ff.findDefaultProfile()
    if err != nil {
        return "", nil
    }
    profile, err = ff.parseProfile(profile)
    if err != nil {
        return "", nil
    }
    return filepath.Join(profile, "cookies.sqlite"), nil
}

func (ff *FireFox) getCookiesFromFile(file string) ([]*http.Cookie, error) {
    tempfile, err := ioutil.TempFile("", "go-webcookies")
    if err != nil {
        return nil, err
    }
    defer os.Remove(tempfile.Name())
    origin, err := os.Open(file)
    if err != nil {
        return nil, err
    }
    if _, err := io.Copy(tempfile, origin); err != nil {
        return nil, err
    }
    tempfile.Close()

    db, err := sql.Open("sqlite3", tempfile.Name())
    if err != nil {
        return nil, err
    }
    defer db.Close()

    rows, err := db.Query("SELECT host, path, isSecure, expiry, name, value FROM moz_cookies")
    if err != nil {
        return nil, err
    }
    cookies := []*http.Cookie{}
    for rows.Next() {
        var host, path, name, value string
        var secure, expiry int
        if err := rows.Scan(&host, &path, &secure, &expiry, &name, &value); err != nil {
            return cookies, err
        }
        cookie := &http.Cookie{
            Name:    name,
            Value:   value,
            Path:    path,
            Domain:  host,
            Expires: time.Unix(int64(expiry), 0),
            Secure:  secure == 1,
        }
        cookies = append(cookies, cookie)
    }
    return cookies, nil
}

func (ff *FireFox) getCookies() ([]*http.Cookie, error) {
    file, err := ff.findCookieFiles()
    if err != nil {
        return nil, err
    }
    return ff.getCookiesFromFile(file)
}

// LoadFireFox will load all your cookies from FireFox.
func LoadFireFox() (*FireFox, error) {
    jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
    if err != nil {
        return nil, err
    }
    ff := &FireFox{jar}
    cookies, err := ff.getCookies()
    if err != nil {
        return nil, err
    }
    for _, cookie := range cookies {
        scheme := "http://"
        if cookie.Secure {
            scheme = "https://"
        }
        u, err := url.Parse(scheme + cookie.Domain + cookie.Path)
        if err != nil {
            return nil, err
        }
        ff.SetCookies(u, []*http.Cookie{cookie})
    }
    return ff, nil
}