#!/usr/bin/envstack{- stack
--resolver lts-12.0
--install-ghc
script
--ghc-options -Werror
--ghc-options -Wall
--
-}--------------------------------------------------------------------------------{-# LANGUAGE EmptyDataDecls #-}{-# LANGUAGE MultiParamTypeClasses #-}{-# LANGUAGE ScopedTypeVariables #-}--------------------------------------------------------------------------------moduleMain(main)where--------------------------------------------------------------------------------importData.List(isInfixOf)--------------------------------------------------------------------------------importSystem.IO.Unsafe(unsafePerformIO)---------------------------------------------------------------------------------- Mandatory Access Control (MAC)--------------------------------------------------------------------------------importqualifiedControl.ExceptionasEximportControl.Monad(ap,liftM)----------------------------------------------------------------------------------------------------------------------------------------------------------------dataP-- PublicdataS-- Secret--------------------------------------------------------------------------------classFlowll'whereclassFlowll'=>Lessll'where--------------------------------------------------------------------------------instanceFlowPPwhereinstanceFlowPSwhereinstanceFlowSSwhereinstanceLessPPwhereinstanceLessPSwhereinstanceLessSSwhere----------------------------------------------------------------------------------------------------------------------------------------------------------------newtypeMACpa=M{mac::IOa}--------------------------------------------------------------------------------instanceFunctor(MACp)wherefmap=liftMinstanceApplicative(MACp)wherepure=return(<*>)=apinstanceMonad(MACp)wherereturna=M$purea(>>=)mf=M$macm>>=mac.f--------------------------------------------------------------------------------lift::IOa->MACpalift=M----------------------------------------------------------------------------------------------------------------------------------------------------------------dataUIDa=U{uid::a}newtypeRESpa=R{res::a}typeLABla=RESl(UIDa)--------------------------------------------------------------------------------label::Lessll'=>a->MACl(LABl'a)label=create.pure.Uwherecreateio=liftio>>=pure.Runlabel::Lessl'l=>LABl'a->MAClaunlabel=readdown$pure.uidwherereaddowniox=lift$io$resx----------------------------------------------------------------------------------------------------------------------------------------------------------------bind::Lessll'=>MACl'a->MACl(LABl'a)bindm=(lift.mac)(trycatchm)>>=labelwheretrycatchx=catchx(\(e::Ex.SomeException)->throwe)throw::Ex.Exceptione=>e->MAClathrow=lift.Ex.throwcatch::Ex.Exceptione=>MACla->(e->MACla)->MAClacatch(Mio)x=lift$Ex.catchio$mac.x------------------------------------------------------------------------------------------------------------------------------------------------------------------ (offline) common pwds library-- Note: For simplicity, replace `wget^MAC` with a simple `offline^MAC`offline::MACPStringoffline=lift$pure-- Top 10 most common passwords:-- https://en.wikipedia.org/wiki/List_of_the_most_common_passwords#SplashData"password\
\123456789\
\111111\
\sunshine\
\qwerty\
\iloveyou"---------------------------------------------------------------------------------- Bob library needs to be in a separated library/module which `must` be marked-- as `SAFE` in order to avoid the usage of `unsafePerformIO` and so.common::LABSString->MACP(LABSBool)commonlpwd=do-- We can't access `lpwd` in the root monad. We need to use the MAC `bind`-- as it allows to operate on data, but it can't leak in the sense that we-- can't send it to the server where we retrieve the passwords.---- * No instance for (Less S P) arising from a use of ‘unlabel’----pwd <- unlabel lpwdoff<-offlinebind$(dopwd<-unlabellpwdpure$(evilpwd)`isInfixOf`off)whereevilx=unsafePerformIO(putStrLnx>>purex)---------------------------------------------------------------------------------- Alicepassword::IOStringpassword=doputStr"Please, select your password: "pwd<-getLineval<-mac$(labelpwd)>>=commonif(uid.res)valthenputStrLn"It's a common password!">>passwordelsepurepwd----------------------------------------------------------------------------------------------------------------------------------------------------------------main::IO()main=password>>=putStrLn.(++)"Valid password is: "