Get z-addr checks working.
[?]
Oct 11, 2020, 3:58 PM
SQ7UMLN5WCPHIF66RO4UQVX6RSNRRZBOVZP7HEMSKP7VO6YNQPRACDependencies
- [2]
MJDIMD5BImprove documentation of local docker-compose setup. - [3]
ENNZIQJGUse live signup API for client. - [4]
BROSTG5KBeginning of modularization of server. - [5]
NSRSSSTRUpdate nginx.conf, make aftok host configurable for cli scripts. - [6]
B6HWAPDPModularize & update to recent haskoin. - [7]
GMYPBCWEMake docker-compose work. - [8]
QADKFHARAdds CreatePayment handler implementation. - [9]
5IDB3IWSIntegrate zcashd-based zaddr validation. - [10]
IZEVQF62Work in progress replacing sqlite with postgres. - [11]
64C6AWH6Rename Ananke -> Quixotic, project reboot. - [12]
NLZ3JXLOFix formatting with stylish-haskell. - [13]
5W5M56VJMove library code to 'lib' - [14]
4U7F3CPITHE GREAT RENAMING OF THINGS! - [15]
QMRKFEPGRefactor QDB to use a free monad algebra instead. - [16]
HMDM3B55Implement core of payments/billing infrastructure. - [17]
KEP5WUFJConvert project to stack-based build. - [18]
AL37SVTCImplement payments service endpoints. - [19]
BSIUHCGFAdd payment response handler. - [20]
4R7XIYK3Switch from ClassyPrelude to Relude - [21]
U256ZALIAdd captcha check to register route. - [22]
ZP62WC47Begin conversion to build with stack. - [23]
SEWTRB6SImplement payment request creation functions. - [24]
ZIG57EE6Fix project selection, end log end on project switch. - [25]
4FDQGIXNMake payment request retrieval key an opaque 32-bit hash. - [26]
IPG33FAWAdd billing daemon - [27]
DFOBMSAOInitial work on payments API - [28]
I2KHGVD4Require project permissions for access to most data. - [29]
UWMGUJOWAutoformat sources. - [30]
NEDDHXUKReformat via stylish-haskell - [31]
JFOEOFGAstylish-haskell formatting. - [32]
WZFQDWW4Add retrieval/storage of current exchange rate data to payment recording. - [33]
LTSVBVA2Update to a recent haskoin-core. Fix Stack build. - [34]
M4KM76DGMerge branch 'stackify' - [35]
BXGLKYRXAdded primitive user registration handler. - [36]
2XQD6KKKAdd invitation logic and clean up DBProg error handling. - [37]
Q5X5RYQLstylish-haskell reformatting - [38]
EFSXYZPOAutoformat everything with brittany. - [39]
UUR6SMCAAdd start of specs for auctions. - [40]
Z7KS5XHHVery WIP. Wow. - [41]
M3KUPGZKAdd invitation email template. - [42]
O2BZOX7MAdd signup form, captcha check. - [43]
HALRDT2FAdded initial auction create route. - [*]
QO4NFWIYAdded sample config file. - [*]
W35DDBFYFactor common JSON conversions up into client lib module. - [*]
V2VDN77HEnable postgres configuration via environment variable for Heroku. - [*]
PBD7LZYQPostgres & auth are beginning to function. - [*]
ADMKQQGCInitial empty Snap project.
Change contents
- replacement in aftok.cabal at line 17
default-extensions: KindSignaturesdefault-extensions: GADTs, KindSignatures - replacement in aftok.cabal at line 34
Aftok.BillablesAftok.Billing - edit in aftok.cabal at line 50
Aftok.Users - replacement in conf/server/aftok.cfg at line 43
zcashdHost = "aftok-zcashd"zcashdPort = 8232rpcHost = "aftok-zcashd"rpcPort = 8232rpcUser = "your_user"rpcPassword = "your_pass" - edit in conf/zcashd/zcash-data/zcash.conf at line 3
rpcuser=your_userrpcpassword=your_pass - replacement in daemon/AftokD/AftokM.hs at line 52
import Aftok.Billables ( Billableimport Aftok.Billing ( Billable - edit in docker-compose.yml at line 69
expose:- "18232" - replacement in docker-compose.yml at line 72
- "8232:8232"- "18232:18232" - file deletion: Users.hs
module Aftok.Users( RegisterOps(..), RegisterError(..))whereimport Aftok.Types (Email(..))import Aftok.Currency.Zcash (ZAddr, ZAddrError)data RegisterError= ZAddrParseError ZAddrErrordata RegisterOps m = RegisterOps, sendConfirmationEmail :: Email -> m ()}{ parseZAddr :: Text -> m (Either ZAddrError ZAddr) - file move: Billables.hs → Billing.hs
- replacement in lib/Aftok/Billing.hs at line 7
module Aftok.Billables wheremodule Aftok.Billing where - replacement in lib/Aftok/Currency/Zcash.hs at line 6
, ZAddrError(..), RPCError(..), ZValidateAddressErr(..) - edit in lib/Aftok/Currency/Zcash.hs at line 9
, Zatoshi, ToZatoshi(..), rpcAddViewingKey - edit in lib/Aftok/Currency/Zcash.hs at line 15
import Control.Exception ( catch ) - edit in lib/Aftok/Currency/Zcash.hs at line 17
import Control.Monad.Trans.Except ( except ) - edit in lib/Aftok/Currency/Zcash.hs at line 26
, HttpException - edit in lib/Aftok/Currency/Zcash.hs at line 32
, applyBasicAuth - edit in lib/Aftok/Currency/Zcash.hs at line 35
coin :: Word64coin = 100000000maxMoney :: Word64maxMoney = 21000000 * coin - edit in lib/Aftok/Currency/Zcash.hs at line 45
newtype Zatoshi = Zatoshi Word64deriving (Eq, Ord, Show)makePrisms ''Zatoshiclass ToZatoshi a wheretoZatoshi :: a -> Maybe Zatoshi - edit in lib/Aftok/Currency/Zcash.hs at line 53
instance ToZatoshi Word64 wheretoZatoshi amt =if amt > maxMoney then Nothing else Just (Zatoshi amt) - edit in lib/Aftok/Currency/Zcash.hs at line 64
, rpcUser :: Text, rpcPassword :: Text - edit in lib/Aftok/Currency/Zcash.hs at line 67
data RPCCall a whereZValidateAddress :: Text -> RPCCall ZValidateAddressRespZImportViewingKey :: Text -> RPCCall ZImportViewingKeyResp - replacement in lib/Aftok/Currency/Zcash.hs at line 72
data ZAddrError= ServiceError Statusdata RPCError e= HttpError HttpException| ServiceError Status - replacement in lib/Aftok/Currency/Zcash.hs at line 76
| ZAddrInvalid| RPCError ederiving (Show)toRequestBody :: RPCCall a -> ValuetoRequestBody = \caseZValidateAddress addr -> validateZAddrRequest addrZImportViewingKey vk -> importViewingKeyRequest vkrpcEval :: A.FromJSON a => Manager -> ZcashdConfig -> RPCCall a -> ExceptT (RPCError e) IO arpcEval mgr cfg call = dolet req = applyBasicAuth (T.encodeUtf8 $ rpcUser cfg) (T.encodeUtf8 $ rpcPassword cfg) $defaultRequest { host = T.encodeUtf8 $ zcashdHost cfg, port = zcashdPort cfg, method = "POST", requestBody = RequestBodyLBS . encode $ toRequestBody call}response <- ExceptT $ catch(Right <$> httpLbs req mgr)(pure . Left . HttpError)let status = responseStatus responseexcept $ case statusCode status of200 -> first ParseError $ A.eitherDecode (responseBody response)_ -> Left (ServiceError status)-- Address Validationdata ZValidateAddressErr= ZAddrInvalid - edit in lib/Aftok/Currency/Zcash.hs at line 108
deriving (Eq, Show)data ZValidateAddressResp = ZValidateAddressResp{ vzrIsValid :: Bool--, vzrAddress :: Maybe Text, vzrAddrType :: Maybe ZAddrType}instance A.FromJSON ZValidateAddressResp whereparseJSON = parseValidateZAddrResponse - replacement in lib/Aftok/Currency/Zcash.hs at line 127
data ValidateZAddrResponse = ValidateZAddrResponse{ isValid :: Bool, _address :: Maybe Text, addrType :: Maybe ZAddrType}instance A.FromJSON ValidateZAddrResponse whereparseJSON = parseValidateZAddrResponseparseAddrType :: Text -> Maybe ZAddrTypeparseAddrType = \casedecodeAddrType :: Text -> Maybe ZAddrTypedecodeAddrType = \case - replacement in lib/Aftok/Currency/Zcash.hs at line 133
parseValidateZAddrResponse :: Value -> Parser ValidateZAddrResponseparseAddrType :: A.Object -> Parser (Maybe ZAddrType)parseAddrType res = dotypeStr <- res .:? "type"let typeMay = decodeAddrType <$> typeStrtraverse (maybe (fail $ "Not a recognized zaddr type: " <> show typeStr) pure) typeMayparseValidateZAddrResponse :: Value -> Parser ZValidateAddressResp - replacement in lib/Aftok/Currency/Zcash.hs at line 141
(A.Object v) ->ValidateZAddrResponse <$> v .: "isvalid"<*> v .:? "address"<*> ((traverse (maybe (fail "Not a recognized zaddr type") pure) . fmap parseAddrType) =<< v .:? "type")(A.Object v) -> dores <- v .: "result"ZValidateAddressResp <$> res .: "isvalid"-- <*> res .:? "address"<*> parseAddrType res - edit in lib/Aftok/Currency/Zcash.hs at line 150
rpcValidateZAddr :: Manager -> ZcashdConfig -> Text -> IO (Either (RPCError ZValidateAddressErr) ZAddr)rpcValidateZAddr mgr cfg addr = runExceptT $ doresp <- rpcEval mgr cfg (ZValidateAddress addr)except $ if vzrIsValid respthencase vzrAddrType resp ofNothing -> Left (RPCError DataMissing)Just Sprout -> Left (RPCError SproutAddress)Just Sapling -> Right (ZAddr addr)elseLeft $ RPCError ZAddrInvalid - replacement in lib/Aftok/Currency/Zcash.hs at line 162
rpcValidateZAddr :: Manager -> ZcashdConfig -> Text -> IO (Either ZAddrError ZAddr)rpcValidateZAddr mgr cfg addr = dolet req = defaultRequest { host = T.encodeUtf8 $ zcashdHost cfg, port = zcashdPort cfg, method = "POST", requestBody = RequestBodyLBS $ encode (validateZAddrRequest addr)}-- Viewing Keys - replacement in lib/Aftok/Currency/Zcash.hs at line 164
response <- httpLbs req mgrlet status = responseStatus responsepure $ case statusCode status of200 ->case A.eitherDecode (responseBody response) ofLeft err -> Left (ParseError err)Right resp ->if isValid respthencase addrType resp ofJust Sprout -> Left SproutAddressJust Sapling -> Right (ZAddr addr)_ -> Left DataMissingelseLeft ZAddrInvalid_ ->Left (ServiceError status)[4.3241]data ZImportViewingKeyResp = ZImportViewingKeyResp{ addressType :: ZAddrType-- , address :: ZAddr}parseImportViewingKeyResponse :: Value -> Parser ZImportViewingKeyRespparseImportViewingKeyResponse = \case(A.Object v) -> doZImportViewingKeyResp<$> (maybe (fail "Missing address type.") pure =<< parseAddrType v)-- <*> (ZAddr <$> v .: "address")_ ->fail "z_importviewingkey response body was not a valid JSON object"instance A.FromJSON ZImportViewingKeyResp whereparseJSON = parseImportViewingKeyResponsedata ZImportViewingKeyError= SproutViewingKeyimportViewingKeyRequest :: Text -> ValueimportViewingKeyRequest vk = object[ "jsonrpc" .= ("1.0" :: Text), "id" .= ("aftok-z_importviewingkey" :: Text), "method" .= ("z_importviewingkey" :: Text), "params" .= [vk, "no"] -- no need to rescan, for our purposes]rpcAddViewingKey :: Manager -> ZcashdConfig -> Text -> IO (Either (RPCError ZImportViewingKeyError) ())rpcAddViewingKey mgr cfg vk = runExceptT $ doresp <- rpcEval mgr cfg (ZImportViewingKey vk)except $ case addressType resp ofSprout -> Left . RPCError $ SproutViewingKeySapling -> Right () - replacement in lib/Aftok/Database/PostgreSQL.hs at line 42
import qualified Aftok.Billables as Bimport qualified Aftok.Billing as B - replacement in lib/Aftok/Database.hs at line 25
import Aftok.Billables as Bimport Aftok.Billing as B - replacement in lib/Aftok/Json.hs at line 44
import qualified Aftok.Billables as Bimport qualified Aftok.Billing as B - replacement in lib/Aftok/Payments/Types.hs at line 30
import Aftok.Billables ( Billableimport Aftok.Billing ( Billable - replacement in lib/Aftok/Payments.hs at line 50[4.3623]→[4.2319:2352](∅→∅),[4.6794]→[4.2319:2352](∅→∅),[4.12295]→[4.2319:2352](∅→∅),[4.27398]→[4.2319:2352](∅→∅),[4.5960]→[4.2319:2352](∅→∅)
import Aftok.Billablesimport Aftok.Billing - replacement in server/Aftok/QConfig.hs at line 73
ZcashdConfig <$> C.require cfg "zcashdHost"<*> C.require cfg "zcashdPort"ZcashdConfig <$> C.require cfg "rpcHost"<*> C.require cfg "rpcPort"<*> C.require cfg "rpcUser"<*> C.require cfg "rpcPassword" - replacement in server/Aftok/Snaplet/Billing.hs at line 20
import Aftok.Billablesimport Aftok.Billing - replacement in server/Aftok/Snaplet/Payments.hs at line 49
import Aftok.Billablesimport Aftok.Billing - replacement in server/Aftok/Snaplet/Users.hs at line 18
import Control.Lensimport Control.Lens ( makeLenses, (^.) ) - edit in server/Aftok/Snaplet/Users.hs at line 23
, (.=) - replacement in server/Aftok/Snaplet/Users.hs at line 42
import Aftok.Currency.Zcash ( ZAddr )import Aftok.Currency.Zcash ( ZAddr, RPCError, ZValidateAddressErr ) - edit in server/Aftok/Snaplet/Users.hs at line 45
import Aftok.Users ( RegisterOps(..) ) - edit in server/Aftok/Snaplet/Users.hs at line 57
data RegisterOps m = RegisterOps{ validateZAddr :: Text -> m (Either (RPCError ZValidateAddressErr) ZAddr), sendConfirmationEmail :: Email -> m ()} - edit in server/Aftok/Snaplet/Users.hs at line 98
data RegisterError= RegParseError String| RegCaptchaError [CaptchaError]| RegZAddrError (RPCError ZValidateAddressErr)instance A.ToJSON RegisterError wheretoJSON = \caseRegParseError msg -> A.object[ "parseError" .= msg ]RegCaptchaError e -> A.object[ "captchaError" .= (show e :: Text) ]RegZAddrError zerr -> A.object[ "zaddrError" .= (show zerr :: Text) ] - replacement in server/Aftok/Snaplet/Users.hs at line 120
zaddrEither <- liftIO $ parseZAddr ops (T.decodeUtf8 zaddrBytes)zaddrEither <- liftIO $ validateZAddr ops (T.decodeUtf8 zaddrBytes) - edit in server/Aftok/Snaplet/Users.hs at line 128
- replacement in server/Aftok/Snaplet/Users.hs at line 134
let captchaFailed = throwDenied $ AU.AuthError "Captcha check failed, please try again."void . either (const captchaFailed) pure $ captchaResultcase captchaResult ofLeft err ->let cmsg = "Captcha check failed, please try again."in snapErrorJS 400 cmsg (RegCaptchaError err)Right _ -> pure () - replacement in server/Aftok/Snaplet/Users.hs at line 145
zaddrValid <- liftIO $ parseZAddr ops zzaddrValid <- liftIO $ validateZAddr ops z - replacement in server/Aftok/Snaplet/Users.hs at line 147
Left _ ->snapError 400 "The Z-Address provided for account recovery was invalid."Left err ->let msg = "The Z-Address provided for account recovery was invalid."in snapErrorJS 400 msg (RegZAddrError err) - edit in server/Aftok/Snaplet/Users.hs at line 180
- replacement in server/Aftok/Snaplet.hs at line 14
import Data.UUIDimport Data.UUID ( UUID, fromASCIIBytes ) - replacement in server/Aftok/Snaplet.hs at line 18[4.7061]→[4.10751:10826](∅→∅),[4.36308]→[4.10751:10826](∅→∅),[4.60405]→[4.10751:10826](∅→∅),[4.10751]→[4.10751:10826](∅→∅)
import Aftok.Databaseimport Aftok.Database.PostgreSQLimport Aftok.Database ( DBError(..), DBOp, liftdb)import Aftok.Database.PostgreSQL ( runQDBM ) - replacement in server/Aftok/Snaplet.hs at line 28
import Snap.Coreimport Snap.Core ( MonadSnap, getParam, readRequestBody, setResponseCode, modifyResponse, finishWith, getResponse, writeText, writeLBS, setResponseStatus, logError) - replacement in server/Aftok/Snaplet.hs at line 42
import Snap.Snaplet.PostgresqlSimpleimport Snap.Snaplet.Sessionimport Snap.Snaplet.PostgresqlSimple ( Postgres, HasPostgres(..), setLocalPostgresState, liftPG)import Snap.Snaplet.Session ( SessionManager ) - edit in server/Aftok/Snaplet.hs at line 49
- replacement in server/Aftok/Snaplet.hs at line 86
modifyResponse $ setResponseStatus c $ encodeUtf8 twriteText $ ((show c) <> " - " <> t)let errBytes = encodeUtf8 tlogError errBytesmodifyResponse $ setResponseStatus c errByteswriteText (show c <> " - " <> t)getResponse >>= finishWithsnapErrorJS :: (A.ToJSON err, MonadSnap m) => Int -> Text -> err -> m asnapErrorJS c t err = dolet errBytes = A.encode errlogError (fromLazy errBytes)modifyResponse $ setResponseStatus c (encodeUtf8 t)writeLBS errBytes - edit in server/Aftok/Snaplet.hs at line 100
- replacement in server/Main.hs at line 51
{ parseZAddr = rpcValidateZAddr mgr (_zcashdConfig cfg){ validateZAddr = rpcValidateZAddr mgr (_zcashdConfig cfg)