|
#lang racket |
|
|
|
(require racket/stxparam |
|
rebellion/base/result |
|
syntax/parse/define) |
|
|
|
(define permission-check-tag (make-continuation-prompt-tag 'permission-check)) |
|
|
|
(define (check-permission-dynamically permission) |
|
(call-with-current-continuation |
|
(λ (jump-back) (abort-current-continuation permission-check-tag permission jump-back)) |
|
permission-check-tag)) |
|
|
|
(define (make-permission-check-handler granted-permissions) |
|
(define (handler permission jump-back) |
|
(if (set-member? granted-permissions permission) |
|
(call-with-continuation-prompt jump-back permission-check-tag handler) |
|
(failure permission))) |
|
handler) |
|
|
|
(define (grant-permissions-dynamically permissions thunk) |
|
(define handler (make-permission-check-handler permissions)) |
|
(call-with-continuation-prompt (λ () (success (thunk))) permission-check-tag handler)) |
|
|
|
(define-syntax-parameter in-grant-permissions-block? #false) |
|
|
|
(define-syntax-parse-rule (check-permission! id:id) |
|
#:fail-unless (syntax-parameter-value #'in-grant-permissions-block?) |
|
"cannot be used outside a grant-permissions block" |
|
(check-permission-dynamically 'id)) |
|
|
|
(define-syntax-parse-rule (grant-permissions (~seq #:allow sym:id) ... body ...) |
|
(grant-permissions-dynamically |
|
(set 'sym ...) |
|
(λ () |
|
(syntax-parameterize ([in-grant-permissions-block? #true]) |
|
body ...)))) |
|
|
|
;; evaluates to (failure 'system-clock) |
|
(grant-permissions |
|
#:allow filesystem |
|
#:allow network |
|
|
|
(displayln "Stealing secret files...") |
|
(check-permission! filesystem) |
|
(displayln "Secret files stolen!") |
|
|
|
(newline) |
|
|
|
(displayln "Contacting the NSA...") |
|
(check-permission! network) |
|
(displayln "NSA contacted!") |
|
|
|
(newline) |
|
|
|
(displayln "Changing the system clock...") |
|
(check-permission! system-clock) |
|
;; this part is never printed |
|
(displayln "System clock changed!")) |
(side note) Regarding the first case, one can also use a simple escape continuation ("ec"):