{"action":"created","comment":{"url":"https://api.github.com/repos/channable/icepeak/pulls/comments/140714541","pull_request_review_id":64823883,"id":140714541,"diff_hunk":"@@ -0,0 +1,116 @@\n+{-# LANGUAGE OverloadedStrings #-}\n+-- | This module provides functionality for verifying the JSON Web Tokens in a wai setting.\n+module JwtMiddleware where\n+\n+import           Control.Applicative\n+import           Control.Monad\n+import           Data.Aeson            ((.=))\n+import qualified Data.Aeson            as Aeson\n+import qualified Data.ByteString       as SBS\n+import qualified Data.ByteString.Lazy  as LBS\n+import qualified Data.List             as List\n+import qualified Data.Text             as Text\n+import           Data.Time.Clock.POSIX (POSIXTime)\n+import qualified Data.Time.Clock.POSIX as Clock\n+import qualified Network.HTTP.Types    as Http\n+import qualified Network.Wai           as Wai\n+import qualified Web.JWT               as JWT\n+\n+import           AccessControl\n+import           JwtAuth\n+import           Store                 (Path)\n+\n+-- | Defines the kinds of errors that cause authorization to fail.\n+data AuthError\n+  = TokenError TokenError\n+    -- ^ Authorization was denied due to an invalid token.\n+  | OperationNotAllowed\n+    -- ^ Authorization was denied because the operation is not allowed by the token.\n+\n+-- | Result of checking authorization\n+data AuthResult\n+  = AuthRejected AuthError\n+    -- ^ Authorization was denied because of the specified reason\n+  | AuthAccepted\n+    -- ^ Authorization was successful\n+\n+-- * Requests\n+\n+-- | Check whether accessing the given path with the given mode is authorized by\n+-- the token supplied in the request headers or query string (which may not be\n+-- present, then failing the check).\n+isRequestAuthorized :: Http.RequestHeaders -> Http.Query -> POSIXTime -> Maybe JWT.Secret -> Path -> AccessMode -> AuthResult\n+isRequestAuthorized headers query now maybeSecret path mode =\n+  case getRequestClaim headers query now maybeSecret of\n+    Left err -> AuthRejected (TokenError err)\n+    Right claim | isAuthorizedByClaim claim path mode\n+                  -> AuthAccepted\n+                | otherwise\n+                  -> AuthRejected OperationNotAllowed\n+\n+-- | Extract the JWT claim from the request.\n+getRequestClaim :: Http.RequestHeaders -> Http.Query -> POSIXTime -> Maybe JWT.Secret -> Either TokenError IcepeakClaim\n+getRequestClaim headers query now maybeSecret =\n+  let getTokenBytes = maybe (Left $ VerificationError TokenNotFound) Right (findTokenBytes headers query)\n+  in case maybeSecret of\n+       -- authorization is enabled, but no secret provided, accept all tokens\n+       Nothing     -> getTokenBytes >>= extractClaimUnverified\n+       Just secret -> getTokenBytes >>= extractClaim now secret","path":"server/src/JwtMiddleware.hs","position":58,"original_position":58,"commit_id":"e53e077d1e2ad68d5a766b8ea2c0ceb74710aefc","original_commit_id":"9f966072ba9065303fb6a9dfae7c5a0c932e88e3","user":{"login":"rightfold","id":5132125,"avatar_url":"https://avatars0.githubusercontent.com/u/5132125?v=4","gravatar_id":"","url":"https://api.github.com/users/rightfold","html_url":"https://github.com/rightfold","followers_url":"https://api.github.com/users/rightfold/followers","following_url":"https://api.github.com/users/rightfold/following{/other_user}","gists_url":"https://api.github.com/users/rightfold/gists{/gist_id}","starred_url":"https://api.github.com/users/rightfold/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rightfold/subscriptions","organizations_url":"https://api.github.com/users/rightfold/orgs","repos_url":"https://api.github.com/users/rightfold/repos","events_url":"https://api.github.com/users/rightfold/events{/privacy}","received_events_url":"https://api.github.com/users/rightfold/received_events","type":"User","site_admin":false},"body":"Make more clear that the comment only applies to the `Nothing` case. For example by moving it in there, or by moving the `Just` case to above the comment.","created_at":"2017-09-25T08:27:21Z","updated_at":"2017-09-25T08:54:31Z","html_url":"https://github.com/channable/icepeak/pull/11#discussion_r140714541","pull_request_url":"https://api.github.com/repos/channable/icepeak/pulls/11","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/channable/icepeak/pulls/comments/140714541"},"html":{"href":"https://github.com/channable/icepeak/pull/11#discussion_r140714541"},"pull_request":{"href":"https://api.github.com/repos/channable/icepeak/pulls/11"}}},"pull_request":{"url":"https://api.github.com/repos/channable/icepeak/pulls/11","id":142606989,"html_url":"https://github.com/channable/icepeak/pull/11","diff_url":"https://github.com/channable/icepeak/pull/11.diff","patch_url":"https://github.com/channable/icepeak/pull/11.patch","issue_url":"https://api.github.com/repos/channable/icepeak/issues/11","number":11,"state":"open","locked":false,"title":"Add support for authentication and authorization through JSON Web Tokens","user":{"login":"fatho","id":3857449,"avatar_url":"https://avatars0.githubusercontent.com/u/3857449?v=4","gravatar_id":"","url":"https://api.github.com/users/fatho","html_url":"https://github.com/fatho","followers_url":"https://api.github.com/users/fatho/followers","following_url":"https://api.github.com/users/fatho/following{/other_user}","gists_url":"https://api.github.com/users/fatho/gists{/gist_id}","starred_url":"https://api.github.com/users/fatho/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fatho/subscriptions","organizations_url":"https://api.github.com/users/fatho/orgs","repos_url":"https://api.github.com/users/fatho/repos","events_url":"https://api.github.com/users/fatho/events{/privacy}","received_events_url":"https://api.github.com/users/fatho/received_events","type":"User","site_admin":false},"body":"For more information, see issue #9.","created_at":"2017-09-22T15:28:04Z","updated_at":"2017-09-25T08:54:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"26e7590fba170b920bff5bc0c579bf51e420749e","assignee":null,"assignees":[],"requested_reviewers":[{"login":"rkrzr","id":82817,"avatar_url":"https://avatars1.githubusercontent.com/u/82817?v=4","gravatar_id":"","url":"https://api.github.com/users/rkrzr","html_url":"https://github.com/rkrzr","followers_url":"https://api.github.com/users/rkrzr/followers","following_url":"https://api.github.com/users/rkrzr/following{/other_user}","gists_url":"https://api.github.com/users/rkrzr/gists{/gist_id}","starred_url":"https://api.github.com/users/rkrzr/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rkrzr/subscriptions","organizations_url":"https://api.github.com/users/rkrzr/orgs","repos_url":"https://api.github.com/users/rkrzr/repos","events_url":"https://api.github.com/users/rkrzr/events{/privacy}","received_events_url":"https://api.github.com/users/rkrzr/received_events","type":"User","site_admin":false},{"login":"NunoAlexandre","id":7075260,"avatar_url":"https://avatars1.githubusercontent.com/u/7075260?v=4","gravatar_id":"","url":"https://api.github.com/users/NunoAlexandre","html_url":"https://github.com/NunoAlexandre","followers_url":"https://api.github.com/users/NunoAlexandre/followers","following_url":"https://api.github.com/users/NunoAlexandre/following{/other_user}","gists_url":"https://api.github.com/users/NunoAlexandre/gists{/gist_id}","starred_url":"https://api.github.com/users/NunoAlexandre/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/NunoAlexandre/subscriptions","organizations_url":"https://api.github.com/users/NunoAlexandre/orgs","repos_url":"https://api.github.com/users/NunoAlexandre/repos","events_url":"https://api.github.com/users/NunoAlexandre/events{/privacy}","received_events_url":"https://api.github.com/users/NunoAlexandre/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/channable/icepeak/pulls/11/commits","review_comments_url":"https://api.github.com/repos/channable/icepeak/pulls/11/comments","review_comment_url":"https://api.github.com/repos/channable/icepeak/pulls/comments{/number}","comments_url":"https://api.github.com/repos/channable/icepeak/issues/11/comments","statuses_url":"https://api.github.com/repos/channable/icepeak/statuses/e53e077d1e2ad68d5a766b8ea2c0ceb74710aefc","head":{"label":"channable:feature/jwt-auth","ref":"feature/jwt-auth","sha":"e53e077d1e2ad68d5a766b8ea2c0ceb74710aefc","user":{"login":"channable","id":1428858,"avatar_url":"https://avatars3.githubusercontent.com/u/1428858?v=4","gravatar_id":"","url":"https://api.github.com/users/channable","html_url":"https://github.com/channable","followers_url":"https://api.github.com/users/channable/followers","following_url":"https://api.github.com/users/channable/following{/other_user}","gists_url":"https://api.github.com/users/channable/gists{/gist_id}","starred_url":"https://api.github.com/users/channable/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/channable/subscriptions","organizations_url":"https://api.github.com/users/channable/orgs","repos_url":"https://api.github.com/users/channable/repos","events_url":"https://api.github.com/users/channable/events{/privacy}","received_events_url":"https://api.github.com/users/channable/received_events","type":"Organization","site_admin":false},"repo":{"id":98553062,"name":"icepeak","full_name":"channable/icepeak","owner":{"login":"channable","id":1428858,"avatar_url":"https://avatars3.githubusercontent.com/u/1428858?v=4","gravatar_id":"","url":"https://api.github.com/users/channable","html_url":"https://github.com/channable","followers_url":"https://api.github.com/users/channable/followers","following_url":"https://api.github.com/users/channable/following{/other_user}","gists_url":"https://api.github.com/users/channable/gists{/gist_id}","starred_url":"https://api.github.com/users/channable/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/channable/subscriptions","organizations_url":"https://api.github.com/users/channable/orgs","repos_url":"https://api.github.com/users/channable/repos","events_url":"https://api.github.com/users/channable/events{/privacy}","received_events_url":"https://api.github.com/users/channable/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/channable/icepeak","description":"Icepeak is a fast Json document store with push notification support.","fork":false,"url":"https://api.github.com/repos/channable/icepeak","forks_url":"https://api.github.com/repos/channable/icepeak/forks","keys_url":"https://api.github.com/repos/channable/icepeak/keys{/key_id}","collaborators_url":"https://api.github.com/repos/channable/icepeak/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/channable/icepeak/teams","hooks_url":"https://api.github.com/repos/channable/icepeak/hooks","issue_events_url":"https://api.github.com/repos/channable/icepeak/issues/events{/number}","events_url":"https://api.github.com/repos/channable/icepeak/events","assignees_url":"https://api.github.com/repos/channable/icepeak/assignees{/user}","branches_url":"https://api.github.com/repos/channable/icepeak/branches{/branch}","tags_url":"https://api.github.com/repos/channable/icepeak/tags","blobs_url":"https://api.github.com/repos/channable/icepeak/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/channable/icepeak/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/channable/icepeak/git/refs{/sha}","trees_url":"https://api.github.com/repos/channable/icepeak/git/trees{/sha}","statuses_url":"https://api.github.com/repos/channable/icepeak/statuses/{sha}","languages_url":"https://api.github.com/repos/channable/icepeak/languages","stargazers_url":"https://api.github.com/repos/channable/icepeak/stargazers","contributors_url":"https://api.github.com/repos/channable/icepeak/contributors","subscribers_url":"https://api.github.com/repos/channable/icepeak/subscribers","subscription_url":"https://api.github.com/repos/channable/icepeak/subscription","commits_url":"https://api.github.com/repos/channable/icepeak/commits{/sha}","git_commits_url":"https://api.github.com/repos/channable/icepeak/git/commits{/sha}","comments_url":"https://api.github.com/repos/channable/icepeak/comments{/number}","issue_comment_url":"https://api.github.com/repos/channable/icepeak/issues/comments{/number}","contents_url":"https://api.github.com/repos/channable/icepeak/contents/{+path}","compare_url":"https://api.github.com/repos/channable/icepeak/compare/{base}...{head}","merges_url":"https://api.github.com/repos/channable/icepeak/merges","archive_url":"https://api.github.com/repos/channable/icepeak/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/channable/icepeak/downloads","issues_url":"https://api.github.com/repos/channable/icepeak/issues{/number}","pulls_url":"https://api.github.com/repos/channable/icepeak/pulls{/number}","milestones_url":"https://api.github.com/repos/channable/icepeak/milestones{/number}","notifications_url":"https://api.github.com/repos/channable/icepeak/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/channable/icepeak/labels{/name}","releases_url":"https://api.github.com/repos/channable/icepeak/releases{/id}","deployments_url":"https://api.github.com/repos/channable/icepeak/deployments","created_at":"2017-07-27T15:33:34Z","updated_at":"2017-09-21T10:55:48Z","pushed_at":"2017-09-25T08:12:49Z","git_url":"git://github.com/channable/icepeak.git","ssh_url":"git@github.com:channable/icepeak.git","clone_url":"https://github.com/channable/icepeak.git","svn_url":"https://github.com/channable/icepeak","homepage":"","size":166,"stargazers_count":6,"watchers_count":6,"language":"Haskell","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":3,"forks":1,"open_issues":3,"watchers":6,"default_branch":"master"}},"base":{"label":"channable:master","ref":"master","sha":"88af42023a54465d8a399bab8cd8b4fc4a896f67","user":{"login":"channable","id":1428858,"avatar_url":"https://avatars3.githubusercontent.com/u/1428858?v=4","gravatar_id":"","url":"https://api.github.com/users/channable","html_url":"https://github.com/channable","followers_url":"https://api.github.com/users/channable/followers","following_url":"https://api.github.com/users/channable/following{/other_user}","gists_url":"https://api.github.com/users/channable/gists{/gist_id}","starred_url":"https://api.github.com/users/channable/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/channable/subscriptions","organizations_url":"https://api.github.com/users/channable/orgs","repos_url":"https://api.github.com/users/channable/repos","events_url":"https://api.github.com/users/channable/events{/privacy}","received_events_url":"https://api.github.com/users/channable/received_events","type":"Organization","site_admin":false},"repo":{"id":98553062,"name":"icepeak","full_name":"channable/icepeak","owner":{"login":"channable","id":1428858,"avatar_url":"https://avatars3.githubusercontent.com/u/1428858?v=4","gravatar_id":"","url":"https://api.github.com/users/channable","html_url":"https://github.com/channable","followers_url":"https://api.github.com/users/channable/followers","following_url":"https://api.github.com/users/channable/following{/other_user}","gists_url":"https://api.github.com/users/channable/gists{/gist_id}","starred_url":"https://api.github.com/users/channable/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/channable/subscriptions","organizations_url":"https://api.github.com/users/channable/orgs","repos_url":"https://api.github.com/users/channable/repos","events_url":"https://api.github.com/users/channable/events{/privacy}","received_events_url":"https://api.github.com/users/channable/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/channable/icepeak","description":"Icepeak is a fast Json document store with push notification support.","fork":false,"url":"https://api.github.com/repos/channable/icepeak","forks_url":"https://api.github.com/repos/channable/icepeak/forks","keys_url":"https://api.github.com/repos/channable/icepeak/keys{/key_id}","collaborators_url":"https://api.github.com/repos/channable/icepeak/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/channable/icepeak/teams","hooks_url":"https://api.github.com/repos/channable/icepeak/hooks","issue_events_url":"https://api.github.com/repos/channable/icepeak/issues/events{/number}","events_url":"https://api.github.com/repos/channable/icepeak/events","assignees_url":"https://api.github.com/repos/channable/icepeak/assignees{/user}","branches_url":"https://api.github.com/repos/channable/icepeak/branches{/branch}","tags_url":"https://api.github.com/repos/channable/icepeak/tags","blobs_url":"https://api.github.com/repos/channable/icepeak/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/channable/icepeak/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/channable/icepeak/git/refs{/sha}","trees_url":"https://api.github.com/repos/channable/icepeak/git/trees{/sha}","statuses_url":"https://api.github.com/repos/channable/icepeak/statuses/{sha}","languages_url":"https://api.github.com/repos/channable/icepeak/languages","stargazers_url":"https://api.github.com/repos/channable/icepeak/stargazers","contributors_url":"https://api.github.com/repos/channable/icepeak/contributors","subscribers_url":"https://api.github.com/repos/channable/icepeak/subscribers","subscription_url":"https://api.github.com/repos/channable/icepeak/subscription","commits_url":"https://api.github.com/repos/channable/icepeak/commits{/sha}","git_commits_url":"https://api.github.com/repos/channable/icepeak/git/commits{/sha}","comments_url":"https://api.github.com/repos/channable/icepeak/comments{/number}","issue_comment_url":"https://api.github.com/repos/channable/icepeak/issues/comments{/number}","contents_url":"https://api.github.com/repos/channable/icepeak/contents/{+path}","compare_url":"https://api.github.com/repos/channable/icepeak/compare/{base}...{head}","merges_url":"https://api.github.com/repos/channable/icepeak/merges","archive_url":"https://api.github.com/repos/channable/icepeak/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/channable/icepeak/downloads","issues_url":"https://api.github.com/repos/channable/icepeak/issues{/number}","pulls_url":"https://api.github.com/repos/channable/icepeak/pulls{/number}","milestones_url":"https://api.github.com/repos/channable/icepeak/milestones{/number}","notifications_url":"https://api.github.com/repos/channable/icepeak/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/channable/icepeak/labels{/name}","releases_url":"https://api.github.com/repos/channable/icepeak/releases{/id}","deployments_url":"https://api.github.com/repos/channable/icepeak/deployments","created_at":"2017-07-27T15:33:34Z","updated_at":"2017-09-21T10:55:48Z","pushed_at":"2017-09-25T08:12:49Z","git_url":"git://github.com/channable/icepeak.git","ssh_url":"git@github.com:channable/icepeak.git","clone_url":"https://github.com/channable/icepeak.git","svn_url":"https://github.com/channable/icepeak","homepage":"","size":166,"stargazers_count":6,"watchers_count":6,"language":"Haskell","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":3,"forks":1,"open_issues":3,"watchers":6,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/channable/icepeak/pulls/11"},"html":{"href":"https://github.com/channable/icepeak/pull/11"},"issue":{"href":"https://api.github.com/repos/channable/icepeak/issues/11"},"comments":{"href":"https://api.github.com/repos/channable/icepeak/issues/11/comments"},"review_comments":{"href":"https://api.github.com/repos/channable/icepeak/pulls/11/comments"},"review_comment":{"href":"https://api.github.com/repos/channable/icepeak/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/channable/icepeak/pulls/11/commits"},"statuses":{"href":"https://api.github.com/repos/channable/icepeak/statuses/e53e077d1e2ad68d5a766b8ea2c0ceb74710aefc"}},"author_association":"NONE"}}
{"actor":{"display_login":"rightfold"}}