{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} module License ( UserTier(..), ToodlesLicense(..), readLicense ) where import Paths_toodles import Data.Aeson import qualified Data.ByteString.Base64.Lazy as B64 import qualified Data.ByteString.Lazy.Char8 as LB import Data.Text (Text) import qualified Data.Text as T import Data.Time.Clock.POSIX import GHC.Generics import System.Directory import System.Exit import System.Process data UserTier = BadLicense String | NoLiscense | Individual | Commercial deriving (Show, Eq, Ord, Generic, ToJSON, FromJSON) data License = License { payload :: ToodlesLicense, encoded :: Text, payloadSignature :: Text } deriving (Generic, FromJSON, ToJSON, Show) data ToodlesLicense = ToodlesLicense { validStart :: Integer , validEnd :: Integer , email :: Text , reference :: Text , product :: Text } deriving (Generic, FromJSON, ToJSON, Show) readLicense :: FilePath -> FilePath -> IO (Either String UserTier) readLicense publicKeyPath licensePath = do licenseExists <- doesFileExist licensePath if not licenseExists then return $ Right NoLiscense else do parsedContents <- eitherDecodeFileStrict licensePath either (return . Left) (isLicenseValid publicKeyPath) parsedContents isLicenseValid :: FilePath -> License -> IO (Either String UserTier) isLicenseValid publicKeyPath (License _ encodedPayload sig) = do dataDir <- getDataDir now <- ((* 1000) . round) `fmap` getPOSIXTime -- dependencies for license verification. for now, python -- TODO(#techdebt) - license verification should be done in haskell, this removed let args = [ dataDir ++ "/verify.py" , publicKeyPath , T.unpack sig , T.unpack encodedPayload ] decodedPayload = decode (B64.decodeLenient . LB.pack $ T.unpack encodedPayload) (exitcode, stdout, stderr) <- readProcessWithExitCode "python" args "" putStrLn stderr return $ let validated = ("True" == T.strip (T.pack stdout)) in if (exitcode == ExitSuccess) && validated && (maybe 0 validEnd decodedPayload >= now) then Right Commercial else Left "Invalid license file"