-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Validate Wordpress Cookies & Nonces; Build Wordpress Hashes & Salts -- -- This package is used for validating Cookie data & Nonces from -- Wordpress. -- -- You may find it useful if you're trying to serve a Haskell application -- alongside a Wordpress site. By validating the Cookies set by -- Wordpress, you can access the currently logged-in Wordpress user in -- Haskell without having to devise a Wordpress-to-Haskell authentication -- scheme. -- -- It includes a generalized authentication function, as well as various -- helpers, validators, & hashers if you'd like to build a custom -- authentication process. -- -- Servant users may want to just use the servant-auth-wordpress -- package. @package wordpress-auth @version 1.0.0.0 -- | The Wordpress.Auth module is used for checking the validity of -- various Wordpress authentication schemes. -- -- This is useful if you want a Haskell application to be able to serve -- authenticated API requests to a Wordpress site without having to -- devise a Wordpress-to-Haskell authentication system. -- -- You will need some constants from your Wordpress site's -- wp-config.php, like the NONCE_KEY & -- NONCE_SALT, you could supply these via environmental -- variables: -- --
-- loggedInScheme <- AuthScheme -- <$> (wpConfigKey . T.pack <$> getEnv "LOGGED_IN_KEY") -- <*> (wpConfigSalt . T.pack <$> getEnv "LOGGED_IN_SALT") ---- -- Then you'll want to pull the specific cookie's text out of the Cookie -- header(see findCookie) & use then -- parseWordpressCookie to build a WPCookie. You should -- then use the username field of the cookie to query your -- Wordpress database for the User's ID(WordpressUserId) -- & user_pass(WordpresUserPass) fields as well as -- the session_tokens User Meta(SessionToken). -- -- Equiped with these and the current time(via getPOSIXTime), you -- can then validate the cookie: -- --
-- passwordFragment = WordpressUserPass myUserTablesUserPassFieldValue -- sessionTokens = decodeSessionTokens myUserMetaTablesSessionTokensMetaValue -- cookieIsValid = validateCookie loggedInScheme currentTime cookie -- passwordFragment sessionTokens ---- -- If this is a REST request or a form submission, you should -- always validate the nonce, even for requests with no auth -- cookies. The nonce can be pulled out of the X-WP-Nonce header -- or the _wpnonce query parameter. -- --
-- nonceTick <- wordpressNonceTick (60 * 60 * 24) currentTime -- let validNonce = validateNonce nonceScheme (Just cookie) nonceTick -- (Just $ WordpressUserId userId) -- "wp_rest" myNonceText --module Wordpress.Auth -- | The is a generalized authentication verification scheme that -- authorizes a user if the logged_in cookie is set and valid, -- & verifies the wp_rest nonce action for both authorized -- & anonymous users. -- -- The WPAuthConfig failure handler will be used if a Cookie is -- present but invalid or if the nonce is missing/invalid. authorizeWordpressRequest :: forall m a. MonadIO m => WPAuthConfig m a -> RequestHeaders -> [QueryItem] -> m (WPAuthorization a) -- | Configuration data specific to your Wordpress site & Haskell -- application. data WPAuthConfig m a WPAuthConfig :: m CookieName -> AuthScheme -> AuthScheme -> NominalDiffTime -> (Text -> m (Maybe (UserAuthData a))) -> (WPAuthError -> m (WPAuthorization a)) -> WPAuthConfig m a -- | A monadic action that generates a CookieName. You can simply -- return a constant value, or do something more complex like querying -- your database for the siteurl option. [getCookieName] :: WPAuthConfig m a -> m CookieName -- | The LOGGED_IN_KEY & LOGGED_IN_SALT from your -- wp-config.php. [loggedInScheme] :: WPAuthConfig m a -> AuthScheme -- | The NONCE_KEY & NONCE_SALT from your -- wp-config.php. [nonceScheme] :: WPAuthConfig m a -> AuthScheme -- | The nonce lifetime of your Wordpress site. Wordpress defaults to 1 -- day. [nonceLifetime] :: WPAuthConfig m a -> NominalDiffTime -- | A function to pull your custom data & the user data needed for -- authentication. See the UserAuthData type. [getUserData] :: WPAuthConfig m a -> Text -> m (Maybe (UserAuthData a)) -- | How to handle authentication failures. You might want to throw an HTTP -- error or simply treat the user as unauthenticated. [onAuthenticationFailure] :: WPAuthConfig m a -> WPAuthError -> m (WPAuthorization a) -- | The data needed for authentication, along with some arbitrary data -- that is returned on success. data UserAuthData a UserAuthData :: a -> WordpressUserId -> WordpressUserPass -> [SessionToken] -> UserAuthData a -- | Arbitrary data that the validation should return. E.g., if you query -- your users table for the ID & user_pass, you can -- return your whole User type so you don't have to make another database -- call in your handler. [userData] :: UserAuthData a -> a -- | The ID field of the User. [wpUser] :: UserAuthData a -> WordpressUserId -- | The user_pass field of the User. [wpPass] :: UserAuthData a -> WordpressUserPass -- | The session_tokens usermeta for the User. You can use -- decodeSessionTokens to parse the raw meta value. [wpTokens] :: UserAuthData a -> [SessionToken] -- | The result of the authorizeWordpressRequest function can be an -- authorized user with some additional data, or an anonymous user. data WPAuthorization a WPAuthorizedUser :: a -> WPAuthorization a WPAnonymousUser :: WPAuthorization a -- | Potential errors during authentication. data WPAuthError -- | Header Error. EHeader :: CookieHeaderError -> WPAuthError -- | Parsing Error. EParse :: CookieParseError -> WPAuthError -- | Validation Error. EValid :: CookieValidationError -> WPAuthError -- | The getUserData function returned Nothing. UserDataNotFound :: WPAuthError -- | The Request has no X-WP-Nonce header. NoNonce :: WPAuthError -- | The nonce couldn't be validated. InvalidNonce :: WPAuthError -- | The name of a Wordpress authentication cookie. Wordpress's frontend -- uses CookieNameWithMD5 "wordpress_logged_in_" -- "<your-site-url>" by default. data CookieName -- | A constant name for the cookie. CustomCookieName :: Text -> CookieName -- | A cookie name with some text to hash & append. E.g., Wordpress's -- logged_in auth scheme uses wordpress_logged_in_ -- suffixed with the MD5 hash of the siteurl option. CookieNameWithMD5 :: Text -> Text -> CookieName -- | Build the name of an authentication cookie from a CookieName, -- hashing the suffix if present. cookieName :: CookieName -> Text -- | Try to find & decode a Cookie in the headers with the given name. findCookie :: CookieName -> RequestHeaders -> Either CookieHeaderError Text -- | Potential errors while searching for a specific cookie in the request -- headers. data CookieHeaderError -- | The Request has no Cookie header. NoCookieHeader :: CookieHeaderError -- | No Cookie matched the expected CookieName. NoCookieMatches :: CookieHeaderError -- | Try to find & decode a Nonce in either the X-WP-Nonce -- header or the _wpnonce query parameter. findNonce :: RequestHeaders -> [QueryItem] -> Maybe Text -- | This represents a Cookie set by a Wordpress authentication scheme -- (auth, auth_sec, & logged_in). data WPCookie WPCookie :: Text -> POSIXTime -> CookieToken -> Text -> WPCookie -- | The user_login column for the Wordpress User. [username] :: WPCookie -> Text -- | The expiration time of the Cookie. [expiration] :: WPCookie -> POSIXTime -- | The Wordpress User's session token. [token] :: WPCookie -> CookieToken -- | A SHA256 HMAC hash of the token & some user data. [hmac] :: WPCookie -> Text -- | A User's Wordpress Session Token from an auth cookie. newtype CookieToken CookieToken :: Text -> CookieToken [cookieToken] :: CookieToken -> Text -- | Parse a WPCookie from the body text of an auth, -- auth_sec, or logged_in cookie. parseWordpressCookie :: Text -> Either CookieParseError WPCookie -- | Potential errors we may encounter while parsing a WPCookie. data CookieParseError -- | The cookie did not have 4 fields separated by `|` characters. MalformedCookie :: CookieParseError -- | The expiration field of the cookie is not an Integer. InvalidExpiration :: CookieParseError -- | Validate a Wordpress Authentication Cookie by verifying that the hash -- & token in the cookie are valid and the expiration time is in the -- future. validateCookie :: AuthScheme -> POSIXTime -> WPCookie -> WordpressUserPass -> [SessionToken] -> Either CookieValidationError () -- | The user_pass field from the users table of a -- Wordpress site. newtype WordpressUserPass WordpressUserPass :: Text -> WordpressUserPass [wordpressUserPass] :: WordpressUserPass -> Text -- | Potential validation errors for a WPCookie. data CookieValidationError -- | The expiration time of the cookie is in the past. CookieExpired :: CookieValidationError -- | The hmac hash in the cookie doesn't match the calculated hash. InvalidHash :: CookieValidationError -- | The token in the cookie is not valid or expired. InvalidToken :: CookieValidationError -- | Determine if a WPCookie's hash matches the hashed password -- & token. -- -- A secret is generated by hashing the user, password, expiration, & -- token. This secret is then used to hash the user, expiration, & -- token. The resulting hash should match the hmac hash in the -- WPCookie. validateCookieHash :: AuthScheme -> WPCookie -> WordpressUserPass -> Bool -- | A User Session's Token. These can be found in the usermeta -- Wordpress table for rows where meta_key="session_token". -- -- You'll probably want to use decodeSessionTokens to parse the -- tables's meta_value instead of constructing them yourself. data SessionToken SessionToken :: Text -> POSIXTime -> SessionToken [sessionToken] :: SessionToken -> Text [tokenExpiration] :: SessionToken -> POSIXTime -- | Decode a serialized PHP array containing a User's Session Tokens. -- These are usually stored as the session_tokens usermeta. -- -- It may be an associative array of tokens to expiration times, or -- tokens to an associative array of sub-fields: -- --
-- array( -- 'some-random-hex-text' => 192836504, -- // ... -- ); -- array( -- 'deadbeef ' => array( -- 'expiration' => 9001, -- // ... -- ), -- ); --decodeSessionTokens :: Text -> [SessionToken] -- | Determine if the SHA256 hash of the token matches one of the unexpired -- session tokens. validateSessionToken :: POSIXTime -> CookieToken -> [SessionToken] -> Bool -- | The tick number of a Wordpress site - required for Nonce verification. newtype NonceTick NonceTick :: Integer -> NonceTick [tickCount] :: NonceTick -> Integer -- | A port of the wp_nonce_tick function. Calculates the nonce -- tick number, where each nonce has a lifetime of two ticks. wordpressNonceTick :: NominalDiffTime -> POSIXTime -> NonceTick -- | Determine if the tick-dependent hash of the CookieToken matches -- the hash of the current or previous tick. validateNonce :: AuthScheme -> Maybe CookieToken -> NonceTick -> Maybe WordpressUserId -> Text -> Text -> Bool -- | The ID field from the users table of a Wordpress -- site. newtype WordpressUserId WordpressUserId :: Integer -> WordpressUserId [wordpressUserId] :: WordpressUserId -> Integer -- | A port of the wp_hash function. This performs an hmac -- hash on some text using a secret derived from the authentication -- scheme's key & salt constants. wordpressHash :: AuthScheme -> Text -> Text -- | A port of the wp_salt function. Builds a secret key for a -- hashing function using the auth scheme's key & salt. wordpressSalt :: AuthScheme -> Text -- | This represents one of the $schemes that Wordpress's -- cookie/nonce functions use to salt their hashes. -- -- The built-in Wordpress schemes are auth/auth_sec for -- HTTP/HTTPS requests to wp-admin, logged_in -- for authenticated front-end requests, & nonce for form -- submissions & API requests. -- -- The secret keys & salts are constants found in your -- wp-config.php file, defined as LOGGED_IN_SALT, -- LOGGED_IN_KEY, etc. data AuthScheme AuthScheme :: WordpressKey -> WordpressSalt -> AuthScheme [schemeKey] :: AuthScheme -> WordpressKey [schemeSalt] :: AuthScheme -> WordpressSalt -- | An auth scheme's _KEY constant, usually defined in your -- Wordpress site's wp-config.php. E.g., LOGGED_IN_KEY data WordpressKey -- | An auth scheme's _SALT constant, usually defined in your -- Wordpress site's wp-config.php. E.g., LOGGED_IN_SALT data WordpressSalt -- | Build the _KEY value for an authentiation scheme. wpConfigKey :: Text -> WordpressKey -- | Build the _SALT value for an authentiation scheme. wpConfigSalt :: Text -> WordpressSalt instance GHC.Classes.Eq Wordpress.Auth.AuthScheme instance GHC.Show.Show Wordpress.Auth.AuthScheme instance GHC.Classes.Eq Wordpress.Auth.WordpressSalt instance GHC.Show.Show Wordpress.Auth.WordpressSalt instance GHC.Classes.Eq Wordpress.Auth.WordpressKey instance GHC.Show.Show Wordpress.Auth.WordpressKey instance GHC.Classes.Eq Wordpress.Auth.NonceTick instance GHC.Show.Show Wordpress.Auth.NonceTick instance GHC.Classes.Eq a => GHC.Classes.Eq (Wordpress.Auth.UserAuthData a) instance GHC.Show.Show a => GHC.Show.Show (Wordpress.Auth.UserAuthData a) instance GHC.Classes.Eq Wordpress.Auth.SessionToken instance GHC.Show.Show Wordpress.Auth.SessionToken instance GHC.Classes.Eq Wordpress.Auth.WPAuthError instance GHC.Show.Show Wordpress.Auth.WPAuthError instance GHC.Classes.Eq Wordpress.Auth.CookieValidationError instance GHC.Show.Show Wordpress.Auth.CookieValidationError instance GHC.Classes.Eq Wordpress.Auth.WordpressUserPass instance GHC.Show.Show Wordpress.Auth.WordpressUserPass instance GHC.Classes.Eq Wordpress.Auth.WordpressUserId instance GHC.Show.Show Wordpress.Auth.WordpressUserId instance GHC.Classes.Eq Wordpress.Auth.CookieParseError instance GHC.Show.Show Wordpress.Auth.CookieParseError instance GHC.Classes.Eq Wordpress.Auth.WPCookie instance GHC.Show.Show Wordpress.Auth.WPCookie instance GHC.Classes.Eq Wordpress.Auth.CookieToken instance GHC.Show.Show Wordpress.Auth.CookieToken instance GHC.Classes.Eq Wordpress.Auth.CookieHeaderError instance GHC.Show.Show Wordpress.Auth.CookieHeaderError instance GHC.Classes.Eq Wordpress.Auth.CookieName instance GHC.Show.Show Wordpress.Auth.CookieName instance GHC.Classes.Eq a => GHC.Classes.Eq (Wordpress.Auth.WPAuthorization a) instance GHC.Show.Show a => GHC.Show.Show (Wordpress.Auth.WPAuthorization a)