aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/data/plugins/cookies.py
blob: 8fb9b3269ad8b688b3802c653d765f7560bd4f27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
""" Basic cookie manager
    forwards cookies to all other instances connected to the event manager"""

from collections import defaultdict
import os, re

symbolic = {'domain': 0, 'path':1, 'name':2, 'value':3, 'scheme':4, 'expires':5}

_splitquoted = re.compile("( |\\\".*?\\\"|'.*?')")
def splitquoted(text):
    return [str(p.strip('\'"')) for p in _splitquoted.split(text) if p.strip()]

# allows for partial cookies
# ? allow wildcard in key
def match(key, cookie):
    for k,c in zip(key,cookie):
        if k != c:
            return False
    return True

class NullStore(object):
    def add_cookie(self, rawcookie, cookie):
        pass

    def delete_cookie(self, rkey, key):
        pass

class ListStore(list):
    def add_cookie(self, rawcookie, cookie):
        self.append(rawcookie)

    def delete_cookie(self, rkey, key):
        self[:] = [x for x in self if not match(key, splitquoted(x))]

class TextStore(object):
    def __init__(self, filename):
        self.filename = filename

    def as_event(self, cookie):
        if cookie[0].startswith("#HttpOnly_"):
            domain = cookie[0][len("#HttpOnly_"):]
        elif cookie[0].startswith('#'):
            return None
        else:
            domain = cookie[0]
        return (domain,
            cookie[2],
            cookie[5],
            cookie[6],
            'https' if cookie[3] == 'TRUE' else 'http',
            cookie[4])

    def as_file(self, cookie):
        return (cookie[0],
            'TRUE' if cookie[0].startswith('.') else 'FALSE',
            cookie[1],
            'TRUE' if cookie[4] == 'https' else 'FALSE',
            cookie[5],
            cookie[2],
            cookie[3])

    def add_cookie(self, rawcookie, cookie):
        assert len(cookie) == 6

        # delete equal cookies (ignoring expire time, value and secure flag)
        self.delete_cookie(None, cookie[:-3])

        first = not os.path.exists(self.filename)
        with open(self.filename, 'a+') as f:
            if first:
                print >> f, "# HTTP Cookie File"
            print >> f, '\t'.join(self.as_file(cookie))

    def delete_cookie(self, rkey, key):
        if not os.path.exists(self.filename):
            return

        # read all cookies
        with open(self.filename, 'r') as f:
            cookies = f.readlines()

        # write those that don't match the cookie to delete
        with open(self.filename, 'w') as f:
            for l in cookies:
                c = self.as_event(l.split('\t'))
                if c is None or not match(key, c):
                    print >> f, l,

xdg_data_home = os.environ.get('XDG_DATA_HOME', os.path.join(os.environ['HOME'], '.local/share'))
DefaultStore = TextStore(os.path.join(xdg_data_home, 'uzbl/cookies.txt'))
SessionStore = TextStore(os.path.join(xdg_data_home, 'uzbl/session-cookies.txt'))

def accept_cookie(uzbl, cookie):
    for component, match in uzbl.cookie_blacklist:
        if match(cookie[component]) is not None:
            return False
    return True

def expires_with_session(uzbl, cookie):
    return cookie[5] == ''

def get_recipents(uzbl):
    """ get a list of Uzbl instances to send the cookie too. """
    # This could be a lot more interesting
    return [u for u in uzbl.parent.uzbls.values() if u is not uzbl]

def get_store(uzbl, session=False):
    if session:
        return SessionStore
    return DefaultStore

def add_cookie(uzbl, cookie):
    splitted = splitquoted(cookie)
    if accept_cookie(uzbl, splitted):
        for u in get_recipents(uzbl):
            u.send('add_cookie %s' % cookie)
        
        get_store(uzbl, expires_with_session(uzbl, splitted)).add_cookie(cookie, splitted)
    else:
        uzbl.send('delete_cookie %s' % cookie)

def delete_cookie(uzbl, cookie):
    for u in get_recipents(uzbl):
        u.send('delete_cookie %s' % cookie)

    splitted = splitquoted(cookie)
    if len(splitted) == 6:
        get_store(uzbl, expires_with_session(uzbl, splitted)).delete_cookie(cookie, splitted)
    else:
        for store in set([get_store(uzbl, session) for session in (True, False)]):
            store.delete_cookie(cookie, splitted)

def blacklist(uzbl, arg):
    component, regexp = splitquoted(arg)
    try:
        component = symbolic[component]
    except KeyError:
        component = int(component)
    assert component <= 5
    uzbl.cookie_blacklist.append((component, re.compile(regexp).match))

def init(uzbl):
    connect_dict(uzbl, {
        'ADD_COOKIE':       add_cookie,
        'DELETE_COOKIE':    delete_cookie,
        'BLACKLIST_COOKIE': blacklist
    })
    export_dict(uzbl, {
        'cookie_blacklist' : []
    })