Extending cookie support with expiration

Providing access to paths on id-cookies

Change PNR to limit checksum updating unless forced
This commit is contained in:
Jay McCarthy 2013-03-07 10:20:11 -07:00
parent 9d3a42f166
commit 6bf03c1244
7 changed files with 71 additions and 37 deletions

View File

@ -55,7 +55,7 @@
(define pkgs-path (build-path root "pkgs")) (define pkgs-path (build-path root "pkgs"))
(make-directory* pkgs-path) (make-directory* pkgs-path)
(define id-cookie-name "id") (define id-cookie-name "pnrid")
;; XXX Add a caching system ;; XXX Add a caching system
(define (package-list) (define (package-list)
@ -172,8 +172,9 @@
=> (λ (user) => (λ (user)
`(span ([id "logout"]) `(span ([id "logout"])
,user ,user
" | " ;;" | "
(a ([href ,(main-url page/logout)]) "logout")))] ;;(a ([href ,(main-url page/logout)]) "logout")
))]
[else [else
""])) ""]))
,@xexpr-forest ,@xexpr-forest
@ -188,7 +189,7 @@
(redirect-to (redirect-to
(main-url page/main) (main-url page/main)
#:headers #:headers
(list (cookie->header (logout-id-cookie id-cookie-name))))) (list (cookie->header (logout-id-cookie id-cookie-name #:path "/")))))
(define (package-list/search ts) (define (package-list/search ts)
(filter (filter
@ -287,7 +288,7 @@
#:headers #:headers
(list (list
(cookie->header (cookie->header
(make-id-cookie id-cookie-name secret-key email))))) (make-id-cookie id-cookie-name secret-key email #:path "/")))))
(when (regexp-match (regexp-quote "/") email) (when (regexp-match (regexp-quote "/") email)
(send/back (send/back
@ -488,7 +489,7 @@
(unless (or (not pkg) (equal? new-pkg pkg)) (unless (or (not pkg) (equal? new-pkg pkg))
(package-remove! pkg)) (package-remove! pkg))
(update-checksum new-pkg) (update-checksum #t new-pkg)
(define new-tag (define new-tag
(request-binding/string pkg-req "tag" #f)) (request-binding/string pkg-req "tag" #f))
@ -680,34 +681,39 @@
(define (page/manage/update req) (define (page/manage/update req)
(update-checksums (update-checksums
#t
(package-list/mine req)) (package-list/mine req))
(redirect-to (main-url page/manage))) (redirect-to (main-url page/manage)))
(define (update-checksums pkgs) (define (update-checksums force? pkgs)
(for-each update-checksum pkgs)) (for-each (curry update-checksum force?) pkgs))
(define (update-checksum pkg-name) (define (update-checksum force? pkg-name)
(define i (package-info pkg-name)) (define i (package-info pkg-name))
(define old-checksum (define old-checksum
(package-ref i 'checksum)) (package-ref i 'checksum))
(define now (current-seconds)) (define now (current-seconds))
(define new-checksum (define last (hash-ref i 'last-checked -inf.0))
(package-url->checksum (when (or force?
(package-ref i 'source) (>= (- now last) (* 24 60 60)))
(list (cons 'client_id (client_id)) (printf "\tupdating ~a\n" pkg-name)
(cons 'client_secret (client_secret))))) (define new-checksum
(package-begin (package-url->checksum
(define* i (package-ref i 'source)
(hash-set i 'checksum (list (cons 'client_id (client_id))
(or new-checksum (cons 'client_secret (client_secret)))))
old-checksum))) (package-begin
(define* i (define* i
(hash-set i 'last-checked now)) (hash-set i 'checksum
(define* i (or new-checksum
(if (and new-checksum (equal? new-checksum old-checksum)) old-checksum)))
i (define* i
(hash-set i 'last-updated now))) (hash-set i 'last-checked now))
(package-info-set! pkg-name i))) (define* i
(if (and new-checksum (equal? new-checksum old-checksum))
i
(hash-set i 'last-updated now)))
(package-info-set! pkg-name i))))
(define basic-start (define basic-start
(planet2-index/basic package-list package-info)) (planet2-index/basic package-list package-info))
@ -719,7 +725,7 @@
(while true (while true
(printf "updating checksums\n") (printf "updating checksums\n")
(with-handlers ([exn:fail? void]) (with-handlers ([exn:fail? void])
(update-checksums (package-list))) (update-checksums #f (package-list)))
;; update once per day based on whenever the server started ;; update once per day based on whenever the server started
(sleep (* 24 60 60))))) (sleep (* 24 60 60)))))
(serve/servlet (serve/servlet

View File

@ -9,3 +9,5 @@ for i in official planet-compat ; do
done done
rsync -a --progress -h --delete --exclude root --exclude compiled --exclude doc ../../planet2/ plt-etc:local/plt/collects/$i/ rsync -a --progress -h --delete --exclude root --exclude compiled --exclude doc ../../planet2/ plt-etc:local/plt/collects/$i/
rsync -a --progress -h --delete --exclude compiled ../../web-server ../../net plt-etc:local/plt/collects/

View File

@ -61,6 +61,7 @@
cookie:add-comment cookie:add-comment
cookie:add-domain cookie:add-domain
cookie:add-max-age cookie:add-max-age
cookie:add-expires
cookie:add-path cookie:add-path
cookie:secure cookie:secure
cookie:version cookie:version
@ -73,7 +74,7 @@
(struct-out cookie-error)) (struct-out cookie-error))
(define-serializable-struct cookie (define-serializable-struct cookie
(name value comment domain max-age path secure version) #:mutable) (name value comment domain max-age path secure version expires) #:mutable)
(define-struct (cookie-error exn:fail) ()) (define-struct (cookie-error exn:fail) ())
;; error* : string args ... -> raises a cookie-error exception ;; error* : string args ... -> raises a cookie-error exception
@ -92,6 +93,7 @@
;; cookie-av = "Comment" "=" value ;; cookie-av = "Comment" "=" value
;; | "Domain" "=" value ;; | "Domain" "=" value
;; | "Max-Age" "=" value ;; | "Max-Age" "=" value
;; | "Expires" "=" value
;; | "Path" "=" value ;; | "Path" "=" value
;; | "Secure" ;; | "Secure"
;; | "Version" "=" 1*DIGIT ;; | "Version" "=" 1*DIGIT
@ -106,6 +108,7 @@
#f ; current path #f ; current path
#f ; normal (non SSL) #f ; normal (non SSL)
#f ; default version #f ; default version
#f ; doesn't expire
))) )))
;;! ;;!
@ -127,7 +130,8 @@
(format-if "Max-Age=~a" (cookie-max-age cookie)) (format-if "Max-Age=~a" (cookie-max-age cookie))
(format-if "Path=~a" (cookie-path cookie)) (format-if "Path=~a" (cookie-path cookie))
(and (cookie-secure cookie) "Secure") (and (cookie-secure cookie) "Secure")
(format "Version=~a" (or (cookie-version cookie) 1)))) (format "Version=~a" (or (cookie-version cookie) 1))
(format-if "expires=~a" (cookie-expires cookie))))
"; ")) "; "))
(define (cookie:add-comment cookie pre-comment) (define (cookie:add-comment cookie pre-comment)
@ -145,6 +149,14 @@
(set-cookie-domain! cookie domain) (set-cookie-domain! cookie domain)
cookie) cookie)
(define (cookie:add-expires cookie expires)
(unless (string? expires)
(error* "invalid expires: ~a" expires))
(unless (cookie? cookie)
(error* "cookie expected, received: ~a" cookie))
(set-cookie-expires! cookie expires)
cookie)
(define (cookie:add-max-age cookie seconds) (define (cookie:add-max-age cookie seconds)
(unless (and (integer? seconds) (not (negative? seconds))) (unless (and (integer? seconds) (not (negative? seconds)))
(error* "invalid Max-Age for cookie: ~a" seconds)) (error* "invalid Max-Age for cookie: ~a" seconds))

View File

@ -64,6 +64,12 @@ that a client should retain the cookie.}
Modifies @racket[cookie] with a path, and also returns Modifies @racket[cookie] with a path, and also returns
@racket[cookie].} @racket[cookie].}
@defproc[(cookie:add-expires [cookie cookie?] [path string])
cookie?]{
Modifies @racket[cookie] with an expiration, and also returns
@racket[cookie].}
@defproc[(cookie:secure [cookie cookie?] [secure boolean?]) @defproc[(cookie:secure [cookie cookie?] [secure boolean?])
cookie?]{ cookie?]{

View File

@ -11,6 +11,7 @@
#:domain (or/c false/c valid-domain?) #:domain (or/c false/c valid-domain?)
#:max-age (or/c false/c exact-nonnegative-integer?) #:max-age (or/c false/c exact-nonnegative-integer?)
#:path (or/c false/c string?) #:path (or/c false/c string?)
#:expires (or/c false/c string?)
#:secure? (or/c false/c boolean?)) #:secure? (or/c false/c boolean?))
. ->* . cookie?)] . ->* . cookie?)]
[cookie->header (cookie? . -> . header?)]) [cookie->header (cookie? . -> . header?)])
@ -31,10 +32,12 @@
#:domain [domain #f] #:domain [domain #f]
#:max-age [max-age #f] #:max-age [max-age #f]
#:path [path #f] #:path [path #f]
#:expires [expires #f]
#:secure? [secure? #f]) #:secure? [secure? #f])
(setter (set-cookie name val) (setter (set-cookie name val)
(cookie:add-comment comment) (cookie:add-comment comment)
(cookie:add-domain domain) (cookie:add-domain domain)
(cookie:add-expires expires)
(cookie:add-max-age max-age) (cookie:add-max-age max-age)
(cookie:add-path path) (cookie:add-path path)
(cookie:secure secure?))) (cookie:secure secure?)))

View File

@ -29,11 +29,12 @@
(and (client-cookie? c) (and (client-cookie? c)
(string=? (client-cookie-name c) name))) (string=? (client-cookie-name c) name)))
(define (make-id-cookie name key data) (define (make-id-cookie name key data #:path [path #f])
(define authored (current-seconds)) (define authored (current-seconds))
(define digest (define digest
(mac key (list authored data))) (mac key (list authored data)))
(make-cookie name (make-cookie name
#:path path
(format "~a&~a&~a" (format "~a&~a&~a"
digest authored data))) digest authored data)))
@ -59,8 +60,8 @@
(for/or ([c (in-list cookies)]) (for/or ([c (in-list cookies)])
(valid-id-cookie? name key timeout c))) (valid-id-cookie? name key timeout c)))
(define (logout-id-cookie name) (define (logout-id-cookie name #:path [path #f])
(make-cookie name "invalid format")) (make-cookie name "invalid format" #:path path #:expires "Thu, 01 Jan 1970 00:00:00 GMT"))
(provide (provide
(contract-out (contract-out
@ -68,11 +69,12 @@
(-> path-string? (-> path-string?
bytes?)] bytes?)]
[logout-id-cookie [logout-id-cookie
(-> cookie-name? cookie?)] (->* (cookie-name?) (#:path string?) cookie?)]
[request-id-cookie [request-id-cookie
(->* (cookie-name? bytes? request?) (->* (cookie-name? bytes? request?)
(#:timeout number?) (#:timeout number?)
(or/c false/c cookie-value?))] (or/c false/c cookie-value?))]
[make-id-cookie [make-id-cookie
(-> cookie-name? bytes? cookie-value? (->* (cookie-name? bytes? cookie-value?)
cookie?)])) (#:path string?)
cookie?)]))

View File

@ -262,6 +262,7 @@ transmission that the server @bold{will not catch}.}
[#:domain domain (or/c false/c valid-domain?) #f] [#:domain domain (or/c false/c valid-domain?) #f]
[#:max-age max-age (or/c false/c exact-nonnegative-integer?) #f] [#:max-age max-age (or/c false/c exact-nonnegative-integer?) #f]
[#:path path (or/c false/c string?) #f] [#:path path (or/c false/c string?) #f]
[#:expires expires (or/c false/c string?) #f]
[#:secure? secure? (or/c false/c boolean?) #f]) [#:secure? secure? (or/c false/c boolean?) #f])
cookie?]{ cookie?]{
Constructs a cookie with the appropriate fields. Constructs a cookie with the appropriate fields.
@ -329,7 +330,8 @@ good entropy, if you care about that sort of thing.
@defproc[(make-id-cookie @defproc[(make-id-cookie
[name cookie-name?] [name cookie-name?]
[secret-salt bytes?] [secret-salt bytes?]
[value cookie-value?]) [value cookie-value?]
[#:path path (or/c false/c string?) #f])
cookie?]{ cookie?]{
Generates an authenticated cookie named @racket[name] containing @racket[value], signed with @racket[secret-salt]. Generates an authenticated cookie named @racket[name] containing @racket[value], signed with @racket[secret-salt].
} }
@ -344,7 +346,8 @@ good entropy, if you care about that sort of thing.
} }
@defproc[(logout-id-cookie @defproc[(logout-id-cookie
[name cookie-name?]) [name cookie-name?]
[#:path path (or/c false/c string?) #f])
cookie?]{ cookie?]{
Generates a cookie named @racket[name] that is not validly authenticated. Generates a cookie named @racket[name] that is not validly authenticated.