File: cookies.lua

package info (click to toggle)
luakit 2012.09.13-r1-8
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,160 kB
  • ctags: 1,276
  • sloc: ansic: 6,086; makefile: 153; ruby: 79; sh: 38
file content (166 lines) | stat: -rw-r--r-- 4,341 bytes parent folder | download
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
------------------------------------------------------------
-- Cross-instance luakit cookie management (with sqlite3) --
-- © 2011 Mason Larobina <mason.larobina@gmail.com>       --
------------------------------------------------------------

local math = require "math"
local string = string
local ipairs = ipairs
local pairs = pairs
local print = print
local lousy = require "lousy"
local capi = {
    luakit = luakit,
    soup = soup,
    sqlite3 = sqlite3,
    timer = timer
}
local time, floor = luakit.time, math.floor

module "cookies"

db_path = capi.luakit.data_dir .. "/cookies.db"

-- Last access time
local atime = 0

-- Set max session age to 3600
session_timeout = 3600
force_session_timeout = true

-- Setup signals on module
lousy.signal.setup(_M, true)

-- Return microseconds from the unixtime epoch
function micro()
    return floor(time() * 1e6)
end

function init()
    -- Return if database handle already open
    if db then return end

    db = capi.sqlite3{ filename = _M.db_path }
    db:exec [[
        PRAGMA synchronous = OFF;
        PRAGMA secure_delete = 1;

        CREATE TABLE IF NOT EXISTS moz_cookies (
            id INTEGER PRIMARY KEY,
            name TEXT,
            value TEXT,
            host TEXT,
            path TEXT,
            expiry INTEGER,
            lastAccessed INTEGER,
            isSecure INTEGER,
            isHttpOnly INTEGER
        );

        CREATE TRIGGER IF NOT EXISTS delete_old_cookie
            BEFORE INSERT ON moz_cookies
            BEGIN
                DELETE FROM moz_cookies
                WHERE (
                    host == new.host AND
                    path == new.path AND
                    name == new.name
                );
            END;
    ]]

    query_all_since = db:compile [[
        SELECT id, name, value, host AS domain, path, expiry AS expires,
            isSecure AS secure, isHttpOnly AS http_only
        FROM moz_cookies
        WHERE lastAccessed >= ? AND expiry >= ?
    ]]

    query_insert = db:compile [[
        INSERT INTO moz_cookies
        VALUES(NULL, ?, ?, ?, ?, ?, ?, ?, ?)
    ]]

    query_expire = db:compile [[
        UPDATE moz_cookies
        SET expiry = 0, value = NULL, lastAccessed = ?
        WHERE host = ? AND path = ? AND name = ?
    ]]

    query_delete_expired = db:compile [[
        DELETE FROM moz_cookies
        WHERE expiry < ? AND lastAccessed < ?
    ]]
end

-- Open database handle after window has time to open
capi.luakit.idle_add(init)

-- Load all cookies after the last check time
capi.soup.add_signal("request-started", function ()
    if not db then init() end

    local old_atime, new_atime = atime, micro()
    -- Rate limit select queries to 1 p/s
    if (new_atime - old_atime) > 1e6 then
        local cookies = query_all_since:exec{ old_atime,
            -- On first exec don't load any expired cookies
            (atime == 0 and time()) or 0 }
        atime = new_atime
        if cookies[1] then
            capi.soup.add_cookies(cookies)
        end
    end
end)

capi.soup.add_signal("cookie-changed", function (old, new)
    if new then
        if _M.emit_signal("accept-cookie", new) == false then
            new.expires = 0 -- expire cookie
            capi.soup.add_cookies{new}
            return
        end

        -- Set session cookie timeout & keep session cookies in memory
        if new.expires == -1 then
            if _M.force_session_timeout then
                new.expires = math.ceil(time() + _M.session_timeout)
                capi.soup.add_cookies{new}
            end
            return
        end

        -- Insert new cookie
        query_insert:exec {
            new.name,
            new.value,
            new.domain,
            new.path,
            new.expires,
            micro(),
            new.secure,
            new.http_only
        }
        return
    end

    -- Expire old cookie
    if old then
        query_expire:exec {
            micro(), -- lastAccessed
            old.domain,
            old.path,
            old.name
        }
    end
end)

-- When closing luakit delete most expired cookies.
capi.luakit.add_signal("can-close", function ()
    if query_delete_expired then
        local t = time()
        query_delete_expired:exec{ t, (t - 86400) * 1e6 }
    end
end)

-- vim: et:sw=4:ts=8:sts=4:tw=80