Skip to content
Permalink
Browse files

Make mozcookiejar public package of leatherman

  • Loading branch information...
frioux committed Apr 6, 2019
1 parent 3fee3e2 commit 9cf2af8c8ab4172ff09900e800a5af1af6a342a8
Showing with 293 additions and 7 deletions.
  1. +0 −1 go.mod
  2. +0 −5 go.sum
  3. +1 −1 internal/tool/expandurl/expandURL.go
  4. +93 −0 pkg/mozcookiejar/cookiejar.go
  5. +157 −0 pkg/mozcookiejar/cookiejar_test.go
  6. +42 −0 pkg/mozcookiejar/examples_test.go
1 go.mod
@@ -4,7 +4,6 @@ require (
github.com/BurntSushi/toml v0.3.1
github.com/PuerkitoBio/goquery v1.5.0
github.com/erikdubbelboer/gspt v0.0.0-20190125194910-e68493906b83
github.com/frioux/mozcookiejar v0.0.2
github.com/frioux/shellquote v0.0.2
github.com/fsnotify/fsnotify v1.4.7
github.com/headzoo/surf v1.0.0
5 go.sum
@@ -9,8 +9,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/erikdubbelboer/gspt v0.0.0-20190125194910-e68493906b83 h1:ngHdSomn2MyugZYKHiycad2xERwIrmMlET7A0lC0UU4=
github.com/erikdubbelboer/gspt v0.0.0-20190125194910-e68493906b83/go.mod h1:v6o7m/E9bfvm79dE1iFiF+3T7zLBnrjYjkWMa1J+Hv0=
github.com/frioux/mozcookiejar v0.0.2 h1:vAPbreMlaQsMPbedqv+h9OUMyLmtwWr9b1LqmOPcEYA=
github.com/frioux/mozcookiejar v0.0.2/go.mod h1:XA6YqSJViOtLsWH5dRSOj6nh/laBXu9EAdGFF6NEE9Q=
github.com/frioux/shellquote v0.0.2 h1:CvQ1aMCS/xhhyGF4JIeA49bhE3W1s5XdBkwmhH3BceQ=
github.com/frioux/shellquote v0.0.2/go.mod h1:1VoFO5LSUNqwAKp2QjSpf9b4PZ4ff+uKXPEjonuyJh8=
github.com/frioux/yaml v0.0.0-20180422015826-390d32f04db5 h1:YMX30YzQ7HSrUMJV8QnQ5toCxoS4lsxD7DjDMUvoa/k=
@@ -32,7 +30,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mmcdole/gofeed v1.0.0-beta2 h1:CjQ0ADhAwNSb08zknAkGOEYqr8zfZKfrzgk9BxpWP2E=
@@ -55,8 +52,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b h1:Elez2XeF2p9uyVj0yEUDqQ56NFcDtcBNkYP7yv8YbUE=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125002852-4b62a64f59f7 h1:F5FmzXi5B/brWpyRV/LcOMeNw1iKcqFh4pqGzCSLqSE=
golang.org/x/net v0.0.0-20190125002852-4b62a64f59f7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -14,7 +14,7 @@ import (
"sync"

"github.com/PuerkitoBio/goquery"
"github.com/frioux/mozcookiejar"
"github.com/frioux/leatherman/pkg/mozcookiejar"
_ "github.com/mattn/go-sqlite3" // sqlite3 required
"github.com/pkg/errors"
"golang.org/x/net/publicsuffix"
@@ -0,0 +1,93 @@
/*
mozcookiejar gives access to cookies stored in SQLite by Mozilla products.
The general idea is that you can log into some website via Firefox (or whatever)
and then have your CLI tools effectively be logged in as well.
It is up to you to create a cookie jar and to connect to the SQLite database.
The example below should make it clear how to safely and correctly do that. I
have tested the github.com/mattn/go-sqlite3 SQLite driver, but I am pretty sure
any of the various SQLite drivers will work.
This library does not support any of the following Cookie fields:
* MaxAge
* HttpOnly
* Raw
* Unparsed
See documentation for the underlying format here: http://kb.mozillazine.org/Cookies.sqlite
*/
package mozcookiejar

/*
Copyright 2018 Arthur Axel fREW Schmidt
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import (
"database/sql"
"fmt"
"net/http"
"net/http/cookiejar"
"net/url"
"time"
)

// LoadIntoJar populates the cookie jar from values in database.
func LoadIntoJar(db *sql.DB, jar *cookiejar.Jar) error {
rows, err := db.Query(
"SELECT host, path, name, value, isSecure, expiry FROM moz_cookies")
if err != nil {
return err
}
defer rows.Close()

for rows.Next() {
var host, path, value, name string
var isSecure bool
var expiry int64

err = rows.Scan(&host, &path, &name, &value, &isSecure, &expiry)
if err != nil {
return err
}

jar.SetCookies(&url.URL{Scheme: "http", Host: host}, []*http.Cookie{{
Name: name,
Value: value,
Secure: isSecure,
Path: path,
Domain: host,

Expires: time.Unix(expiry, 0),
RawExpires: fmt.Sprintf("%d", expiry),

// Intentionally Left Blank
// * MaxAge
// * HttpOnly
// * Raw
// * Unparsed
}})
}
err = rows.Err()
if err != nil {
return err
}

return nil
}

// func Store(jar *cookiejar.Jar) error {
// return nil
// }
@@ -0,0 +1,157 @@
package mozcookiejar

import (
"database/sql"
"net/http/cookiejar"
"net/url"
"testing"

_ "github.com/mattn/go-sqlite3" // sqlite3 required
)

const year3018 = 33059825142

func freshDBAndJar(t *testing.T) (*sql.DB, *cookiejar.Jar) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatalf("Couldn't create db: %s", err)
}
_, err = db.Exec(`
CREATE TABLE moz_cookies (
id INTEGER PRIMARY KEY,
name TEXT,
value TEXT,
host TEXT,
path TEXT,
expiry INTEGER,
isSecure INTEGER
)`)
if err != nil {
t.Fatalf("Couldn't create table: %s", err)
}
jar, err := cookiejar.New(nil)
if err != nil {
t.Fatalf("Couldn't create cookiejar: %s", err)
}
return db, jar
}

func insert(t *testing.T, db *sql.DB, name, value, host, path string, expiry int, isSecure int) {
_, err := db.Exec(
`INSERT INTO moz_cookies
(name, value, host, path, expiry, isSecure)
VALUES (?, ?, ?, ?, ?, ?)`,
name, value, host, path, expiry, isSecure)
if err != nil {
t.Fatalf("Couldn't create record: %s", err)
}
}

func urlFromString(t *testing.T, urlStr string) *url.URL {
ret, err := url.Parse(urlStr)
if err != nil {
t.Fatalf("Couldn't parse URL: %s", err)
}
return ret
}

func TestBasic(t *testing.T) {
db, jar := freshDBAndJar(t)
insert(t, db, "a", "b", "www.foo.com", "/frew", year3018, 1)
insert(t, db, "c", "d", "www.bar.com", "/frioux", year3018, 0)
err := LoadIntoJar(db, jar)
if err != nil {
t.Fatalf("Couldn't populate cookiejar: %s", err)
}

c := jar.Cookies(urlFromString(t, "https://x.y.foo.com/frew"))
if len(c) > 0 {
t.Error("Domain worked")
}

c = jar.Cookies(urlFromString(t, "https://www.foo.com/"))
if len(c) > 0 {
t.Error("path worked")
}

c = jar.Cookies(urlFromString(t, "http://www.foo.com/frew"))
if len(c) > 0 {
t.Error("isSecure worked")
}

c = jar.Cookies(urlFromString(t, "https://www.foo.com/frew"))
if len(c) == 0 {
t.Error("Normal access works")
}
}

func TestMutli(t *testing.T) {
db, jar := freshDBAndJar(t)
insert(t, db, "a", "b", "www.foo.com", "/frew", year3018, 1)
insert(t, db, "c", "d", "www.foo.com", "/frew", year3018, 1)
err := LoadIntoJar(db, jar)
if err != nil {
t.Fatalf("Couldn't populate cookiejar: %s", err)
}

c := jar.Cookies(urlFromString(t, "https://x.y.foo.com/frew"))
if len(c) > 0 {
t.Error("Domain worked")
t.Log(c)
}

c = jar.Cookies(urlFromString(t, "https://www.foo.com/"))
if len(c) > 0 {
t.Error("path worked")
}

c = jar.Cookies(urlFromString(t, "http://www.foo.com/frew"))
if len(c) > 0 {
t.Error("isSecure worked")
}

c = jar.Cookies(urlFromString(t, "https://www.foo.com/frew"))
if len(c) != 2 {
t.Error("Normal access works")
}
}

func TestInvalidDB(t *testing.T) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
t.Fatalf("Couldn't create db: %s", err)
}
_, err = db.Exec(`
CREATE TABLE invalid_db (
id INTEGER PRIMARY KEY,
name TEXT,
value TEXT
)`)
if err != nil {
t.Fatalf("Couldn't create table: %s", err)
}
jar, err := cookiejar.New(nil)
if err != nil {
t.Fatalf("Couldn't create cookiejar: %s", err)
}
err = LoadIntoJar(db, jar)
if err == nil {
t.Error("Invalid db should surface an error")
}
}

func TestInvalidData(t *testing.T) {
db, jar := freshDBAndJar(t)
_, err := db.Exec(
`INSERT INTO moz_cookies
(name, value, host, path, expiry, isSecure)
VALUES (?, ?, ?, ?, ?, ?)`,
"a", "b", ".frew.com", "/", "explode", 0)
if err != nil {
t.Fatalf("Couldn't create record: %s", err)
}
err = LoadIntoJar(db, jar)
if err == nil {
t.Error("Invalid record should surface an error")
}
}
@@ -0,0 +1,42 @@
package mozcookiejar_test

import (
"database/sql"
"fmt"
"io"
"net/http"
"net/http/cookiejar"
"os"

"github.com/frioux/leatherman/pkg/mozcookiejar"
_ "github.com/mattn/go-sqlite3" // sqlite3 required
"golang.org/x/net/publicsuffix"
)

func Example() {
jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to build cookies: %s\n", err)
os.Exit(1)
}
db, err := sql.Open("sqlite3", os.Getenv("MOZ_COOKIEJAR"))
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to open db: %s\n", err)
os.Exit(1)
}
defer db.Close()

err = mozcookiejar.LoadIntoJar(db, jar)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to load cookies: %s\n", err)
os.Exit(1)
}
ua := http.Client{Jar: jar}

resp, err := ua.Get("https://some.authenticated.com/website")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fetch page: %s\n", err)
os.Exit(1)
}
io.Copy(os.Stdout, resp.Body)
}

0 comments on commit 9cf2af8

Please sign in to comment.
You can’t perform that action at this time.