Compare commits

..

42 commits

Author SHA1 Message Date
ea731df20d
Merge branch 'security1' 2023-06-26 11:28:33 -05:00
9376d959f8
New version preparation 2023-06-26 11:27:27 -05:00
6ae6dd8430
Update payment confirmation for new API endpoint 2023-06-26 09:50:12 -05:00
e0c07091e9
Fix WooCommerce callback 2023-06-23 14:16:56 -05:00
51471cd58f
adjust WooCommerce callback 2023-06-23 13:13:20 -05:00
5ffb1b4a83
Add debugging to WooCommerce endpoint 2023-06-23 11:45:07 -05:00
7672cdc083
Update WooCommerce endpoint 2023-06-23 11:26:03 -05:00
ac0e74c818
Correct invdata check of correct creation 2023-06-22 16:51:58 -05:00
b49a996bf5
Correct session generation for Xero orders 2023-06-22 16:39:31 -05:00
013feabd20
Correct Xero payment confirmation 2023-06-22 16:16:33 -05:00
6e0cb54032
Add check of existing order 2023-06-22 13:38:33 -05:00
4bd49c76d4
Correct Zcash price handling in invdata 2023-06-22 11:52:36 -05:00
fb0144bbe1
Correct currency check in invdata 2023-06-22 10:10:19 -05:00
cd93f0031d
Correct HTTP codes for invdata 2023-06-22 08:26:55 -05:00
87efbf0613
Correct type of ownerId in XeroInvoiceRequest 2023-06-21 16:09:04 -05:00
547d5511fa
Add languange endpoint for pmtservice 2023-06-21 15:49:23 -05:00
b638b4bbce
Add shop name to invdata 2023-06-21 14:59:34 -05:00
bd4d611d04
Enhance invdata endpoint for Xero invoices 2023-06-21 14:29:41 -05:00
f29c5ecb03
Rebuild invdata endpoint for Xero invoices 2023-06-21 11:15:30 -05:00
aa3794b504
Modify xero endpoints 2023-06-20 13:27:53 -05:00
f469ed6763
Add shop name to receipt endpoint 2023-06-20 08:54:28 -05:00
f632b48f32
Add parameter for confirmation window 2023-06-20 07:54:24 -05:00
aff5e4f03d
Add more debugging to payment confirmation 2023-06-19 18:54:18 -05:00
ae198541ee
Add debugging to order payment 2023-06-19 18:06:21 -05:00
9a87d43459
Fix problem with payment confirmations 2023-06-19 17:54:21 -05:00
f21700f88b
Improve payment confirmation 2023-06-19 16:58:39 -05:00
e35304f030
Adjust CORS 2023-06-16 14:00:22 -05:00
05d0042a60
Add tests for new viewing key endpoint 2023-06-16 10:22:38 -05:00
9f64683474
Implement new endpoint for viewing keys
Mantis Issue 28
2023-06-15 19:40:58 -05:00
353c91204a
Enhance payment confirmation logic 2023-06-15 08:55:39 -05:00
c2fc8b8ae9
Add tests for random WooToken 2023-06-12 15:48:23 -05:00
e4e95b81b2
Add new JSON serialization for WooToken 2023-06-12 15:09:13 -05:00
f625373e2e
Harden the wootoken endpoints 2023-06-09 10:51:42 -05:00
33df90eb96
Correct order endpoints 2023-06-05 07:47:51 -05:00
88ae856195
Add random token for orders 2023-06-02 13:51:17 -05:00
31eb42c1d5
Upgrade Haskell packages 2023-06-02 13:49:03 -05:00
9d81bd7472
Order endpoints corrections 2023-06-01 14:59:50 -05:00
c8f1d250b5
Add tests for Item endpoints 2023-05-26 14:04:35 -05:00
857a298b96
Enhance GET items 2023-05-25 11:15:21 -05:00
958f04ee11
Harden user endpoints and corresponding tests 2023-05-17 11:46:24 -05:00
ee95038a44
Update tests 2023-05-17 09:44:25 -05:00
9f13cbf302
Correct order payment logic 2023-05-16 14:27:10 -05:00
18 changed files with 1295 additions and 426 deletions

View file

@ -4,7 +4,39 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.5.0] ## [1.7.0]
### Added
- Parameter to config for number of confirmations for scan
- Endpoint for language for invoices
### Changed
- Modified payment confirmation to use new WooCommerce plugin API endpoint.
- Consolidated the `invdata`, `orderid` and `orderx` endpoints
- The `xerotoken` endpoint uses `session` for authentication
- The order by ID/token endpoint includes shop name
### Fixed
- The viewing key obfuscation of blank viewing keys
## [1.6.0]
### Added
- New JSON serialization for WooTokens.
- New `/api/ownervk` endpoint to save viewing keys
- Use of `zcash-haskell` library to validate Sapling viewing keys
### Changed
- Modified the process of scanning for payments to only scan addresses that have an active ZGo session and have enabled payment confirmations
- Modified the process to mark paid orders to ensure only payments to the shop's wallet get marked as paid
- Modified the `items` endpoint to use the login session to identify records
## [1.5.0] - 2023-05-15
### Added ### Added

View file

@ -6,7 +6,8 @@ The API server behind the [ZGo.cash](https://zgo.cash) app.
## Dependencies ## Dependencies
- Zcash Full node - Zcash Full node (`zcashd`)
- [Zcash Haskell](https://git.vergara.tech/Vergara_Tech/zcash-haskell)
- MongoDB - MongoDB
## Configuration ## Configuration

View file

@ -1,5 +1,5 @@
name: zgo-backend name: zgo-backend
version: 1.5.0 version: 1.7.0
git: "https://git.vergara.tech/Vergara_Tech/zgo-backend" git: "https://git.vergara.tech/Vergara_Tech/zgo-backend"
license: BOSL license: BOSL
author: "Rene Vergara" author: "Rene Vergara"
@ -62,6 +62,7 @@ library:
- crypto-rng - crypto-rng
- megaparsec - megaparsec
- uuid - uuid
- zcash-haskell
executables: executables:
zgo-backend-exe: zgo-backend-exe:
@ -161,3 +162,6 @@ tests:
- time - time
- configurator - configurator
- scotty - scotty
- megaparsec
- uuid
- zcash-haskell

View file

@ -26,6 +26,7 @@ data Config =
, c_smtpPort :: Integer , c_smtpPort :: Integer
, c_smtpUser :: String , c_smtpUser :: String
, c_smtpPwd :: String , c_smtpPwd :: String
, c_confirmations :: Integer
} }
deriving (Eq, Show) deriving (Eq, Show)
@ -48,6 +49,7 @@ loadZGoConfig path = do
mailPort <- require config "smtpPort" mailPort <- require config "smtpPort"
mailUser <- require config "smtpUser" mailUser <- require config "smtpUser"
mailPwd <- require config "smtpPwd" mailPwd <- require config "smtpPwd"
conf <- require config "confirmations"
return $ return $
Config Config
dbHost dbHost
@ -66,3 +68,4 @@ loadZGoConfig path = do
mailPort mailPort
mailUser mailUser
mailPwd mailPwd
conf

View file

@ -12,6 +12,7 @@ import Data.Time.Clock
import Database.MongoDB import Database.MongoDB
import GHC.Generics import GHC.Generics
import Test.QuickCheck import Test.QuickCheck
import User
-- | Type to represent a ZGo item -- | Type to represent a ZGo item
data Item = data Item =
@ -87,6 +88,9 @@ findItems :: T.Text -> Action IO [Document]
findItems a = findItems a =
rest =<< find (select ["owner" =: a] "items") {sort = ["name" =: (1 :: Int)]} rest =<< find (select ["owner" =: a] "items") {sort = ["name" =: (1 :: Int)]}
findItemById :: String -> Action IO (Maybe Document)
findItemById i = findOne (select ["_id" =: (read i :: ObjectId)] "items")
upsertItem :: Item -> Action IO () upsertItem :: Item -> Action IO ()
upsertItem i = do upsertItem i = do
let item = val i let item = val i

View file

@ -29,11 +29,12 @@ data ZGoOrder =
, qpaid :: Bool , qpaid :: Bool
, qexternalInvoice :: T.Text , qexternalInvoice :: T.Text
, qshortCode :: T.Text , qshortCode :: T.Text
, qtoken :: T.Text
} }
deriving (Eq, Show, Generic) deriving (Eq, Show, Generic)
instance ToJSON ZGoOrder where instance ToJSON ZGoOrder where
toJSON (ZGoOrder i a s ts c cur p t tZ l paid eI sC) = toJSON (ZGoOrder i a s ts c cur p t tZ l paid eI sC tk) =
case i of case i of
Just oid -> Just oid ->
object object
@ -50,6 +51,7 @@ instance ToJSON ZGoOrder where
, "paid" .= paid , "paid" .= paid
, "externalInvoice" .= eI , "externalInvoice" .= eI
, "shortCode" .= sC , "shortCode" .= sC
, "token" .= tk
] ]
Nothing -> Nothing ->
object object
@ -66,6 +68,7 @@ instance ToJSON ZGoOrder where
, "paid" .= paid , "paid" .= paid
, "externalInvoice" .= eI , "externalInvoice" .= eI
, "shortCode" .= sC , "shortCode" .= sC
, "token" .= tk
] ]
instance FromJSON ZGoOrder where instance FromJSON ZGoOrder where
@ -84,6 +87,7 @@ instance FromJSON ZGoOrder where
pd <- obj .: "paid" pd <- obj .: "paid"
eI <- obj .: "externalInvoice" eI <- obj .: "externalInvoice"
sC <- obj .: "shortCode" sC <- obj .: "shortCode"
tk <- obj .: "token"
pure $ pure $
ZGoOrder ZGoOrder
(if not (null i) (if not (null i)
@ -101,9 +105,10 @@ instance FromJSON ZGoOrder where
pd pd
eI eI
sC sC
tk
instance Val ZGoOrder where instance Val ZGoOrder where
val (ZGoOrder i a s ts c cur p t tZ l pd eI sC) = val (ZGoOrder i a s ts c cur p t tZ l pd eI sC tk) =
if isJust i if isJust i
then Doc then Doc
[ "_id" =: i [ "_id" =: i
@ -119,6 +124,7 @@ instance Val ZGoOrder where
, "paid" =: pd , "paid" =: pd
, "externalInvoice" =: eI , "externalInvoice" =: eI
, "shortCode" =: sC , "shortCode" =: sC
, "token" =: tk
] ]
else Doc else Doc
[ "address" =: a [ "address" =: a
@ -133,6 +139,7 @@ instance Val ZGoOrder where
, "paid" =: pd , "paid" =: pd
, "externalInvoice" =: eI , "externalInvoice" =: eI
, "shortCode" =: sC , "shortCode" =: sC
, "token" =: tk
] ]
cast' (Doc d) = do cast' (Doc d) = do
i <- B.lookup "_id" d i <- B.lookup "_id" d
@ -148,7 +155,8 @@ instance Val ZGoOrder where
pd <- B.lookup "paid" d pd <- B.lookup "paid" d
eI <- B.lookup "externalInvoice" d eI <- B.lookup "externalInvoice" d
sC <- B.lookup "shortCode" d sC <- B.lookup "shortCode" d
Just (ZGoOrder i a s ts c cur p t tZ l pd eI sC) tk <- B.lookup "token" d
Just (ZGoOrder i a s ts c cur p t tZ l pd eI sC tk)
cast' _ = Nothing cast' _ = Nothing
-- Type to represent an order line item -- Type to represent an order line item
@ -224,12 +232,17 @@ updateOrderTotals o =
(qpaid o) (qpaid o)
(qexternalInvoice o) (qexternalInvoice o)
(qshortCode o) (qshortCode o)
(qtoken o)
where where
newTotal :: ZGoOrder -> Double newTotal :: ZGoOrder -> Double
newTotal x = foldr tallyItems 0 (qlines x) newTotal x = foldr tallyItems 0 (qlines x)
tallyItems :: LineItem -> Double -> Double tallyItems :: LineItem -> Double -> Double
tallyItems y z = (lqty y * lcost y) + z tallyItems y z = (lqty y * lcost y) + z
setOrderToken :: T.Text -> ZGoOrder -> ZGoOrder
setOrderToken token (ZGoOrder i a s ts c cur p t tZ l pd eI sC tk) =
ZGoOrder i a s ts c cur p t tZ l pd eI sC token
findOrder :: T.Text -> Action IO (Maybe Document) findOrder :: T.Text -> Action IO (Maybe Document)
findOrder s = findOne (select ["session" =: s, "closed" =: False] "orders") findOrder s = findOne (select ["session" =: s, "closed" =: False] "orders")

View file

@ -366,8 +366,12 @@ instance ToJSON OwnerSettings where
, "expiration" .= e , "expiration" .= e
, "payconf" .= pc , "payconf" .= pc
, "crmToken" .= cT , "crmToken" .= cT
, "viewkey" .= (T.take 8 vK <> "...." <> T.takeEnd 8 vK) , "viewkey" .= keyObfuscate vK
] ]
where
keyObfuscate s
| s == "" = ""
| otherwise = T.take 8 s <> "...." <> T.takeEnd 8 s
-- Helper Functions -- Helper Functions
getOwnerSettings :: Owner -> OwnerSettings getOwnerSettings :: Owner -> OwnerSettings
@ -407,6 +411,10 @@ findOwnerById :: T.Text -> Action IO (Maybe Document)
findOwnerById i = findOwnerById i =
findOne (select ["_id" =: (read (T.unpack i) :: ObjectId)] "owners") findOne (select ["_id" =: (read (T.unpack i) :: ObjectId)] "owners")
findActiveOwners :: Action IO [Document]
findActiveOwners =
rest =<< find (select ["paid" =: True, "payconf" =: True] "owners")
-- | Function to find Owners about to expire -- | Function to find Owners about to expire
findExpiringOwners :: UTCTime -> Action IO [Document] findExpiringOwners :: UTCTime -> Action IO [Document]
findExpiringOwners now = findExpiringOwners now =
@ -437,6 +445,10 @@ updateOwnerSettings os =
] ]
] ]
upsertViewingKey :: Owner -> String -> Action IO ()
upsertViewingKey o vk =
modify (select ["_id" =: o_id o] "owners") ["$set" =: ["viewKey" =: vk]]
-- | Type for a pro session -- | Type for a pro session
data ZGoProSession = data ZGoProSession =
ZGoProSession ZGoProSession

View file

@ -69,6 +69,36 @@ instance FromJSON User where
"" ""
v v
instance Val User where
cast' (Doc d) = do
i <- B.lookup "_id" d
a <- B.lookup "address" d
s <- B.lookup "session" d
b <- B.lookup "blocktime" d
p <- B.lookup "pin" d
v <- B.lookup "validated" d
Just $ User i a s b p v
cast' _ = Nothing
val (User i a s b p v) =
case i of
Just oid ->
Doc
[ "_id" =: oid
, "address" =: a
, "session" =: s
, "blocktime" =: b
, "pin" =: p
, "validated" =: v
]
Nothing ->
Doc
[ "address" =: a
, "session" =: s
, "blocktime" =: b
, "pin" =: p
, "validated" =: v
]
parseUserBson :: B.Document -> Maybe User parseUserBson :: B.Document -> Maybe User
parseUserBson d = do parseUserBson d = do
i <- B.lookup "_id" d i <- B.lookup "_id" d
@ -84,6 +114,9 @@ parseUserBson d = do
findUser :: T.Text -> Action IO (Maybe Document) findUser :: T.Text -> Action IO (Maybe Document)
findUser s = findOne (select ["session" =: s] "users") findUser s = findOne (select ["session" =: s] "users")
findUserById :: String -> Action IO (Maybe Document)
findUserById i = findOne (select ["_id" =: (read i :: B.ObjectId)] "users")
-- | Function to delete user by ID -- | Function to delete user by ID
deleteUser :: String -> Action IO () deleteUser :: String -> Action IO ()
deleteUser i = deleteOne (select ["_id" =: (read i :: B.ObjectId)] "users") deleteUser i = deleteOne (select ["_id" =: (read i :: B.ObjectId)] "users")

View file

@ -28,6 +28,29 @@ data WooToken =
} }
deriving (Eq, Show) deriving (Eq, Show)
instance FromJSON WooToken where
parseJSON =
withObject "WooToken" $ \obj -> do
i <- obj .:? "_id"
o <- obj .: "ownerid"
t <- obj .: "token"
u <- obj .: "siteurl"
pure $ WooToken (read <$> i) (read o) t u
instance ToJSON WooToken where
toJSON (WooToken i o t u) =
case i of
Just oid ->
object
["_id" .= show oid, "ownerid" .= show o, "token" .= t, "siteurl" .= u]
Nothing ->
object
[ "_id" .= ("" :: String)
, "ownerid" .= show o
, "token" .= t
, "siteurl" .= u
]
instance Val WooToken where instance Val WooToken where
val (WooToken i o t u) = val (WooToken i o t u) =
if isJust i if isJust i
@ -47,8 +70,11 @@ instance Val WooToken where
cast' _ = Nothing cast' _ = Nothing
-- Database actions -- Database actions
findWooToken :: ObjectId -> Action IO (Maybe Document) findWooToken :: Maybe ObjectId -> Action IO (Maybe Document)
findWooToken oid = findOne (select ["owner" =: oid] "wootokens") findWooToken oid =
case oid of
Nothing -> return Nothing
Just o -> findOne (select ["owner" =: o] "wootokens")
addUrl :: WooToken -> T.Text -> Action IO () addUrl :: WooToken -> T.Text -> Action IO ()
addUrl t u = addUrl t u =
@ -63,8 +89,9 @@ payWooOrder ::
-> BS.ByteString -- Total ZEC for order -> BS.ByteString -- Total ZEC for order
-> IO () -> IO ()
payWooOrder u i o t p z = do payWooOrder u i o t p z = do
wooReq <- parseRequest $ u ++ "/wc-api/zpmtcallback" wooReq <- parseRequest u
let req = let req =
setRequestPath "/wp-json/wc/v3/zgocallback" $
setRequestQueryString setRequestQueryString
[ ("token", Just t) [ ("token", Just t)
, ("orderid", Just o) , ("orderid", Just o)
@ -77,23 +104,15 @@ payWooOrder u i o t p z = do
res <- httpLBS req res <- httpLBS req
if getResponseStatus res == ok200 if getResponseStatus res == ok200
then return () then return ()
else error "Failed to report payment to WooCommerce" else do
print $ getResponseStatus res
error "Failed to report payment to WooCommerce"
generateWooToken :: Owner -> Action IO () generateWooToken :: Owner -> String -> Action IO ()
generateWooToken o = generateWooToken o s =
case o_id o of case o_id o of
Just ownerid -> do Just ownerid -> do
let tokenHash = let wooToken = val $ WooToken Nothing ownerid (T.pack s) Nothing
BLK.hash
[ BA.pack . BS.unpack . C.pack . T.unpack $ oname o <> oaddress o :: BA.Bytes
]
let wooToken =
val $
WooToken
Nothing
ownerid
(T.pack . show $ (tokenHash :: BLK.Digest BLK.DEFAULT_DIGEST_LEN))
Nothing
case wooToken of case wooToken of
Doc wT -> insert_ "wootokens" wT Doc wT -> insert_ "wootokens" wT
_ -> error "Couldn't create the WooCommerce token" _ -> error "Couldn't create the WooCommerce token"

View file

@ -171,6 +171,26 @@ instance FromJSON XeroTenant where
--u <- obj .: "updatedDateUtc" --u <- obj .: "updatedDateUtc"
pure $ XeroTenant i aei tI tT tN pure $ XeroTenant i aei tI tT tN
data XeroInvoiceRequest =
XeroInvoiceRequest
{ xr_owner :: T.Text
, xr_invNo :: T.Text
, xr_amount :: Double
, xr_currency :: T.Text
, xr_shortCode :: T.Text
}
deriving (Show, Eq)
instance FromJSON XeroInvoiceRequest where
parseJSON =
withObject "XeroInvoiceRequest" $ \obj -> do
o <- obj .: "ownerId"
i <- obj .: "invoice"
a <- obj .: "amount"
c <- obj .: "currency"
s <- obj .: "shortcode"
pure $ XeroInvoiceRequest o i a c s
data XeroInvoice = data XeroInvoice =
XeroInvoice XeroInvoice
{ xi_id :: Maybe ObjectId { xi_id :: Maybe ObjectId
@ -443,5 +463,6 @@ payXeroInvoice pipe dbName inv address amt zec = do
setRequestHost "api.xero.com" $ setRequestHost "api.xero.com" $
setRequestMethod "PUT" defaultRequest setRequestMethod "PUT" defaultRequest
res <- httpJSON req :: IO (Response Object) res <- httpJSON req :: IO (Response Object)
print res
return () return ()
else error "Invalid parameters" else error "Invalid parameters"

View file

@ -12,6 +12,8 @@ import Control.Concurrent (forkIO, threadDelay)
import Control.Exception (try) import Control.Exception (try)
import Control.Monad import Control.Monad
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Crypto.RNG (newCryptoRNGState, runCryptoRNGT)
import Crypto.RNG.Utils (randomString)
import Data.Aeson import Data.Aeson
import Data.Array import Data.Array
import qualified Data.Bson as B import qualified Data.Bson as B
@ -37,7 +39,7 @@ import qualified Data.UUID as U
import qualified Data.Vector as V import qualified Data.Vector as V
import Data.Vector.Internal.Check (doChecks) import Data.Vector.Internal.Check (doChecks)
import Data.Word import Data.Word
import Database.MongoDB import Database.MongoDB hiding (Order)
import Debug.Trace import Debug.Trace
import GHC.Generics import GHC.Generics
import Item import Item
@ -64,6 +66,9 @@ import Web.Scotty
import WooCommerce import WooCommerce
import Xero import Xero
import ZGoTx import ZGoTx
import ZcashHaskell.Sapling
import ZcashHaskell.Types (RawData(..))
import ZcashHaskell.Utils (decodeBech32)
-- Models for API objects -- Models for API objects
-- | A type to model Zcash RPC calls -- | A type to model Zcash RPC calls
@ -586,7 +591,7 @@ routes pipe config = do
simpleCorsResourcePolicy simpleCorsResourcePolicy
{ corsRequestHeaders = ["Authorization", "Content-Type"] { corsRequestHeaders = ["Authorization", "Content-Type"]
, corsMethods = "DELETE" : simpleMethods , corsMethods = "DELETE" : simpleMethods
--, corsOrigins = Nothing , corsOrigins = Nothing
} }
middleware $ middleware $
basicAuth basicAuth
@ -623,56 +628,221 @@ routes pipe config = do
]) ])
get "/api/xerotoken" $ do get "/api/xerotoken" $ do
code <- param "code" code <- param "code"
address <- param "address" session <- param "session"
user <- liftAndCatchIO $ run (findUser session)
xeroConfig <- liftAndCatchIO $ run findXero xeroConfig <- liftAndCatchIO $ run findXero
case xeroConfig of case cast' . Doc =<< xeroConfig of
Nothing -> status noContent204
Just x -> do
let xConfig = cast' (Doc x)
case xConfig of
Nothing -> status noContent204 Nothing -> status noContent204
Just c -> do Just c -> do
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
res <- res <-
liftAndCatchIO $ liftAndCatchIO $
requestXeroToken pipe (c_dbName config) c code address requestXeroToken pipe (c_dbName config) c code $ uaddress u
if res if res
then status ok200 then status ok200
else status noContent204 else status noContent204
get "/api/invdata" $ do post "/invdata" $ do
inv <- param "inv" invData <- jsonData
oAddress <- param "address"
xeroConfig <- liftAndCatchIO $ run findXero xeroConfig <- liftAndCatchIO $ run findXero
case xeroConfig of let invReq = payload (invData :: Payload XeroInvoiceRequest)
case cast' . Doc =<< xeroConfig of
Nothing -> do Nothing -> do
status noContent204 status ok200
text "Xero App credentials not found" Web.Scotty.json
Just x -> do (object
let xConfig = cast' (Doc x) [ "reportType" .= (1 :: Integer)
case xConfig of , "order" .= (Nothing :: Maybe ZGoOrder)
Nothing -> do , "shop" .= (Nothing :: Maybe String)
status noContent204 ])
text "Xero App credentials corrupted"
Just c -> do Just c -> do
o <- liftAndCatchIO $ run $ findOwnerById $ xr_owner invReq
case cast' . Doc =<< o of
Nothing -> do
status ok200
Web.Scotty.json
(object
[ "reportType" .= (2 :: Integer)
, "order" .= (Nothing :: Maybe ZGoOrder)
, "shop" .= (Nothing :: Maybe String)
])
Just o' -> do
existingOrder <-
liftAndCatchIO $
run $
findXeroOrder
(oaddress o')
(xr_invNo invReq)
(xr_shortCode invReq)
case cast' . Doc =<< existingOrder of
Nothing -> do
res <- res <-
liftAndCatchIO $ liftAndCatchIO $
requestXeroToken pipe (c_dbName config) c "none" oAddress requestXeroToken pipe (c_dbName config) c "none" $ oaddress o'
if res if res
then do then do
resInv <- resInv <-
liftAndCatchIO $ liftAndCatchIO $
getXeroInvoice pipe (c_dbName config) inv oAddress getXeroInvoice pipe (c_dbName config) (xr_invNo invReq) $
oaddress o'
case resInv of case resInv of
Nothing -> do Nothing -> do
status noContent204
text "Xero invoice not found"
Just xI -> do
status ok200 status ok200
Web.Scotty.json (object ["invdata" .= toJSON xI]) Web.Scotty.json
else status noContent204 (object
[ "reportType" .= (2 :: Integer)
, "order" .= (Nothing :: Maybe ZGoOrder)
, "shop" .= (Nothing :: Maybe String)
])
Just xI -> do
if xi_type xI == "ACCREC"
then if xi_status xI == "AUTHORISED"
then if xi_currency xI ==
T.toUpper (ocurrency o')
then if xi_total xI == xr_amount invReq
then do
now <- liftIO getCurrentTime
tk <- liftIO generateToken
pr <-
liftAndCatchIO $
run
(findPrice $
T.unpack . ocurrency $ o')
case parseZGoPrice =<< pr of
Nothing -> do
status ok200
Web.Scotty.json
(object
[ "reportType" .=
(7 :: Integer)
, "order" .=
(Nothing :: Maybe ZGoOrder)
, "shop" .=
(Nothing :: Maybe String)
])
Just cp -> do
let newOrder =
ZGoOrder
Nothing
(oaddress o')
("Xero-" <>
maybe
""
(T.pack . show)
(o_id o'))
now
True
(ocurrency o')
(price cp)
(xi_total xI)
(xi_total xI /
price cp)
[ LineItem
1
("Invoice from " <>
oname o' <>
" [" <>
xi_number xI <>
"]")
(xi_total xI)
]
False
(xi_number xI)
(xr_shortCode
invReq)
(T.pack tk)
_ <-
liftAndCatchIO $
run $
upsertOrder newOrder
finalOrder <-
liftAndCatchIO $
run $
findXeroOrder
(oaddress o')
(xi_number xI)
(xr_shortCode invReq)
case cast' . Doc =<<
finalOrder of
Nothing -> do
status
internalServerError500
text
"Unable to save order to DB"
Just fO -> do
status created201
Web.Scotty.json
(object
[ "reportType" .=
(0 :: Integer)
, "order" .=
toJSON
(fO :: ZGoOrder)
, "shop" .=
oname o'
])
else do
status ok200
Web.Scotty.json
(object
[ "reportType" .=
(8 :: Integer)
, "order" .=
(Nothing :: Maybe ZGoOrder)
, "shop" .=
(Nothing :: Maybe String)
])
else do
status ok200
Web.Scotty.json
(object
[ "reportType" .= (7 :: Integer)
, "order" .=
(Nothing :: Maybe ZGoOrder)
, "shop" .=
(Nothing :: Maybe String)
])
else do
status ok200
Web.Scotty.json
(object
[ "reportType" .= (6 :: Integer)
, "order" .= (Nothing :: Maybe ZGoOrder)
, "shop" .= (Nothing :: Maybe String)
])
else do
status ok200
Web.Scotty.json
(object
[ "reportType" .= (5 :: Integer)
, "order" .= (Nothing :: Maybe ZGoOrder)
, "shop" .= (Nothing :: Maybe String)
])
else do
status ok200
Web.Scotty.json
(object
[ "reportType" .= (1 :: Integer)
, "order" .= (Nothing :: Maybe ZGoOrder)
, "shop" .= (Nothing :: Maybe String)
])
Just eO -> do
status created201
Web.Scotty.json
(object
[ "reportType" .= (0 :: Integer)
, "order" .= toJSON (eO :: ZGoOrder)
, "shop" .= oname o'
])
-- Get the xeroaccount code -- Get the xeroaccount code
get "/api/xeroaccount" $ do get "/api/xeroaccount" $ do
oAdd <- param "address" session <- param "session"
res <- liftAndCatchIO $ run (findToken oAdd) user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
res <- liftAndCatchIO $ run (findToken $ uaddress u)
let c = cast' . Doc =<< res let c = cast' . Doc =<< res
case c of case c of
Nothing -> status noContent204 Nothing -> status noContent204
@ -685,14 +855,27 @@ routes pipe config = do
]) ])
-- Save the xeroaccount code -- Save the xeroaccount code
post "/api/xeroaccount" $ do post "/api/xeroaccount" $ do
oAdd <- param "address" session <- param "session"
c <- param "code" c <- param "code"
user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
let oAdd = uaddress u
liftAndCatchIO $ run (addAccCode oAdd c) liftAndCatchIO $ run (addAccCode oAdd c)
status accepted202 status accepted202
-- Get the WooCommerce token -- Get the WooCommerce token
get "/api/wootoken" $ do get "/api/wootoken" $ do
oid <- param "ownerid" session <- param "session"
res <- liftAndCatchIO $ run (findWooToken (read oid)) user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
owner <- liftAndCatchIO $ run (findOwner $ uaddress u)
case cast' . Doc =<< owner of
Nothing -> status internalServerError500
Just o -> do
res <- liftAndCatchIO $ run (findWooToken $ o_id o)
let t1 = cast' . Doc =<< res let t1 = cast' . Doc =<< res
case t1 of case t1 of
Nothing -> status noContent204 Nothing -> status noContent204
@ -706,19 +889,27 @@ routes pipe config = do
]) ])
post "/api/wootoken" $ do post "/api/wootoken" $ do
oid <- param "ownerid" oid <- param "ownerid"
session <- param "session"
user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
res <- liftAndCatchIO $ run (findOwnerById oid) res <- liftAndCatchIO $ run (findOwnerById oid)
let o1 = cast' . Doc =<< res case cast' . Doc =<< res of
case o1 of Nothing -> status badRequest400
Nothing -> status noContent204
Just o -> do Just o -> do
liftAndCatchIO $ run (generateWooToken o) if oaddress o == uaddress u
then do
tk <- liftIO generateToken
liftAndCatchIO $ run (generateWooToken o tk)
status accepted202 status accepted202
else status forbidden403
-- Authenticate the WooCommerce plugin -- Authenticate the WooCommerce plugin
get "/auth" $ do get "/auth" $ do
oid <- param "ownerid" oid <- param "ownerid"
t <- param "token" t <- param "token"
siteurl <- param "siteurl" siteurl <- param "siteurl"
res <- liftAndCatchIO $ run (findWooToken (read oid)) res <- liftAndCatchIO $ run (findWooToken $ Just (read oid))
let c1 = cast' . Doc =<< res let c1 = cast' . Doc =<< res
case c1 of case c1 of
Nothing -> do Nothing -> do
@ -727,7 +918,7 @@ routes pipe config = do
(object (object
["authorized" .= False, "message" .= ("Owner not found" :: String)]) ["authorized" .= False, "message" .= ("Owner not found" :: String)])
Just c -> Just c ->
if t == w_token c if blk3Hash t == blk3Hash (T.unpack $ w_token c)
then if isNothing (w_url c) then if isNothing (w_url c)
then do then do
liftAndCatchIO $ run (addUrl c siteurl) liftAndCatchIO $ run (addUrl c siteurl)
@ -765,6 +956,10 @@ routes pipe config = do
[ "authorized" .= False [ "authorized" .= False
, "message" .= ("Token mismatch" :: String) , "message" .= ("Token mismatch" :: String)
]) ])
where blk3Hash :: String -> String
blk3Hash s =
show
(BLK.hash [BA.pack . BS.unpack . C.pack $ s :: BA.Bytes] :: BLK.Digest BLK.DEFAULT_DIGEST_LEN)
get "/woopayment" $ do get "/woopayment" $ do
oid <- param "ownerid" oid <- param "ownerid"
t <- param "token" t <- param "token"
@ -774,7 +969,7 @@ routes pipe config = do
amount <- param "amount" amount <- param "amount"
sUrl <- param "siteurl" sUrl <- param "siteurl"
orderKey <- param "orderkey" orderKey <- param "orderkey"
res <- liftAndCatchIO $ run (findWooToken (read oid)) res <- liftAndCatchIO $ run (findWooToken $ Just (read oid))
let c = cast' . Doc =<< res let c = cast' . Doc =<< res
case c of case c of
Nothing -> do Nothing -> do
@ -806,6 +1001,7 @@ routes pipe config = do
Just o -> Just o ->
if opaid o if opaid o
then do then do
tk <- liftIO generateToken
let newOrder = let newOrder =
ZGoOrder ZGoOrder
Nothing Nothing
@ -832,9 +1028,11 @@ routes pipe config = do
(T.concat (T.concat
[T.pack sUrl, "-", ordId, "-", orderKey]) [T.pack sUrl, "-", ordId, "-", orderKey])
"" ""
(T.pack tk)
newId <- liftAndCatchIO $ run (insertWooOrder newOrder) newId <- liftAndCatchIO $ run (insertWooOrder newOrder)
status ok200 status ok200
Web.Scotty.json (object ["order" .= show newId]) Web.Scotty.json
(object ["order" .= show newId, "token" .= tk])
else do else do
status accepted202 status accepted202
Web.Scotty.json Web.Scotty.json
@ -893,12 +1091,20 @@ routes pipe config = do
--Delete user --Delete user
Web.Scotty.delete "/api/user/:id" $ do Web.Scotty.delete "/api/user/:id" $ do
userId <- param "id" userId <- param "id"
session <- param "session"
let r = mkRegex "^[a-f0-9]{24}$" let r = mkRegex "^[a-f0-9]{24}$"
if matchTest r userId if matchTest r userId
then do
u <- liftAndCatchIO $ run (findUserById userId)
case cast' . Doc =<< u of
Nothing -> status badRequest400
Just u' ->
if session == usession u'
then do then do
liftAndCatchIO $ run (deleteUser userId) liftAndCatchIO $ run (deleteUser userId)
status ok200 status ok200
else status noContent204 else status forbidden403
else status badRequest400
--Get current blockheight from Zcash node --Get current blockheight from Zcash node
get "/blockheight" $ do get "/blockheight" $ do
blockInfo <- blockInfo <-
@ -929,7 +1135,7 @@ routes pipe config = do
[ "message" .= ("Owner found!" :: String) [ "message" .= ("Owner found!" :: String)
, "owner" .= getOwnerSettings o , "owner" .= getOwnerSettings o
]) ])
get "/api/ownerid" $ do get "/ownerid" $ do
id <- param "id" id <- param "id"
owner <- liftAndCatchIO $ run (findOwnerById id) owner <- liftAndCatchIO $ run (findOwnerById id)
case owner of case owner of
@ -943,23 +1149,7 @@ routes pipe config = do
Web.Scotty.json Web.Scotty.json
(object (object
[ "message" .= ("Owner found!" :: String) [ "message" .= ("Owner found!" :: String)
, "owner" .= , "owner" .= getOwnerSettings q
object
[ "_id" .= (maybe "" show $ o_id q :: String)
, "address" .= oaddress q
, "name" .= oname q
, "currency" .= ocurrency q
, "tax" .= otax q
, "taxValue" .= otaxValue q
, "vat" .= ovat q
, "vatValue" .= ovatValue q
, "paid" .= opaid q
, "zats" .= ozats q
, "invoices" .= oinvoices q
, "expiration" .= oexpiration q
, "payconf" .= opayconf q
, "crmToken" .= ocrmToken q
]
]) ])
--Upsert owner to DB --Upsert owner to DB
post "/api/owner" $ do post "/api/owner" $ do
@ -1015,10 +1205,58 @@ routes pipe config = do
liftAndCatchIO $ run $ updateOwnerSettings q liftAndCatchIO $ run $ updateOwnerSettings q
status accepted202 status accepted202
else status noContent204 else status noContent204
post "/api/ownervk" $ do
s <- param "session"
u <- liftAndCatchIO $ run (findUser s)
o <- jsonData
let q = payload (o :: Payload String)
let qRaw = decodeBech32 $ C.pack q
if hrp qRaw == "fail"
then status badRequest400
else do
let qBytes = bytes qRaw
case cast' . Doc =<< u of
Nothing -> status unauthorized401
Just u' -> do
if isValidSaplingViewingKey qBytes
then if matchSaplingAddress
qBytes
(bytes . decodeBech32 . C.pack . T.unpack $ uaddress u')
then do
owner <- liftAndCatchIO $ run (findOwner $ uaddress u')
case cast' . Doc =<< owner of
Nothing -> status badRequest400
Just o' -> do
unless (oviewkey o' /= "") $ do
vkInfo <-
liftAndCatchIO $
makeZcashCall
nodeUser
nodePwd
"z_importviewingkey"
[ Data.Aeson.String (T.strip . T.pack $ q)
, "no"
]
let content =
getResponseBody vkInfo :: RpcResponse Object
if isNothing (err content)
then do
_ <-
liftAndCatchIO $ run (upsertViewingKey o' q)
status created201
else do
text $ L.pack . show $ err content
status badRequest400
else status forbidden403
else status badRequest400
--Get items associated with the given address --Get items associated with the given address
get "/api/items" $ do get "/api/items" $ do
addr <- param "address" session <- param "session"
items <- liftAndCatchIO $ run (findItems addr) user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status forbidden403
Just u -> do
items <- liftAndCatchIO $ run (findItems $ uaddress u)
case items of case items of
[] -> status noContent204 [] -> status noContent204
_ -> do _ -> do
@ -1026,22 +1264,40 @@ routes pipe config = do
status ok200 status ok200
Web.Scotty.json Web.Scotty.json
(object (object
["message" .= ("Items found!" :: String), "items" .= toJSON pItems]) [ "message" .= ("Items found!" :: String)
, "items" .= toJSON pItems
])
--Upsert item --Upsert item
post "/api/item" $ do post "/api/item" $ do
i <- jsonData i <- jsonData
session <- param "session"
user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status forbidden403
Just u -> do
let q = payload (i :: Payload Item) let q = payload (i :: Payload Item)
if uaddress u == iowner q
then do
_ <- liftAndCatchIO $ run (upsertItem q) _ <- liftAndCatchIO $ run (upsertItem q)
status created201 status created201
else status forbidden403
--Delete item --Delete item
Web.Scotty.delete "/api/item/:id" $ do Web.Scotty.delete "/api/item/:id" $ do
session <- param "session"
oId <- param "id" oId <- param "id"
let r = mkRegex "^[a-f0-9]{24}$" u' <- liftAndCatchIO $ checkUser run session
if matchTest r oId case u' of
Nothing -> status forbidden403
Just u -> do
i <- liftAndCatchIO $ run (findItemById oId)
case cast' . Doc =<< i of
Nothing -> status badRequest400
Just i' -> do
if iowner i' == uaddress u
then do then do
liftAndCatchIO $ run (deleteItem oId) liftAndCatchIO $ run (deleteItem oId)
status ok200 status ok200
else status noContent204 else status forbidden403
--Get price for Zcash --Get price for Zcash
get "/price" $ do get "/price" $ do
curr <- param "currency" curr <- param "currency"
@ -1057,8 +1313,12 @@ routes pipe config = do
]) ])
--Get all closed orders for the address --Get all closed orders for the address
get "/api/allorders" $ do get "/api/allorders" $ do
addr <- param "address" session <- param "session"
myOrders <- liftAndCatchIO $ run (findAllOrders addr) user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
myOrders <- liftAndCatchIO $ run (findAllOrders $ uaddress u)
case myOrders of case myOrders of
[] -> status noContent204 [] -> status noContent204
_ -> do _ -> do
@ -1070,26 +1330,31 @@ routes pipe config = do
, "orders" .= toJSON pOrders , "orders" .= toJSON pOrders
]) ])
--Get order by id for receipts --Get order by id for receipts
get "/api/order/:id" $ do get "/order/:id" $ do
oId <- param "id" oId <- param "id"
token <- param "token"
let r = mkRegex "^[a-f0-9]{24}$" let r = mkRegex "^[a-f0-9]{24}$"
if matchTest r oId if matchTest r oId
then do then do
myOrder <- liftAndCatchIO $ run (findOrderById oId) myOrder <- liftAndCatchIO $ run (findOrderById oId)
case myOrder of case cast' . Doc =<< myOrder of
Nothing -> status noContent204 Nothing -> status noContent204
Just o -> do
let o' = cast' (Doc o)
case o' of
Nothing -> status internalServerError500
Just pOrder -> do Just pOrder -> do
if qtoken pOrder == token
then do
shop <- liftAndCatchIO $ run (findOwner $ qaddress pOrder)
case cast' . Doc =<< shop of
Nothing -> status badRequest400
Just s -> do
status ok200 status ok200
Web.Scotty.json Web.Scotty.json
(object (object
[ "message" .= ("Order found!" :: String) [ "message" .= ("Order found!" :: String)
, "order" .= toJSON (pOrder :: ZGoOrder) , "order" .= toJSON (pOrder :: ZGoOrder)
, "shop" .= (oname s :: T.Text)
]) ])
else status noContent204 else status forbidden403
else status badRequest400
--Get order by session --Get order by session
get "/api/order" $ do get "/api/order" $ do
sess <- param "session" sess <- param "session"
@ -1132,13 +1397,37 @@ routes pipe config = do
post "/api/order" $ do post "/api/order" $ do
newOrder <- jsonData newOrder <- jsonData
let q = payload (newOrder :: Payload ZGoOrder) let q = payload (newOrder :: Payload ZGoOrder)
session <- param "session"
user <- liftAndCatchIO $ run (findUser session)
case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
if uaddress u == qaddress q
then do
if qtoken q == ""
then do
t <- liftIO generateToken
_ <-
liftAndCatchIO $
run (upsertOrder $ setOrderToken (T.pack t) q)
status created201
else do
_ <- liftAndCatchIO $ run (upsertOrder q) _ <- liftAndCatchIO $ run (upsertOrder q)
status created201 status created201
else status forbidden403
--Delete order --Delete order
Web.Scotty.delete "/api/order/:id" $ do Web.Scotty.delete "/api/order/:id" $ do
oId <- param "id" oId <- param "id"
session <- param "session"
o <- liftAndCatchIO $ run (findOrderById oId)
case cast' . Doc =<< o of
Nothing -> status badRequest400
Just order -> do
if qsession order == session
then do
liftAndCatchIO $ run (deleteOrder oId) liftAndCatchIO $ run (deleteOrder oId)
status ok200 status ok200
else status forbidden403
-- Get language for component -- Get language for component
get "/getmainlang" $ do get "/getmainlang" $ do
lang <- param "lang" lang <- param "lang"
@ -1164,6 +1453,22 @@ routes pipe config = do
Just textPack -> do Just textPack -> do
status ok200 status ok200
Web.Scotty.json $ toJSON (textPack :: LangComponent) Web.Scotty.json $ toJSON (textPack :: LangComponent)
get "/getinvoicelang" $ do
lang <- param "lang"
txtPack' <- liftAndCatchIO $ run (findLangComponent lang "invoice")
case cast' . Doc =<< txtPack' of
Nothing -> status noContent204
Just textPack -> do
status ok200
Web.Scotty.json $ toJSON (textPack :: LangComponent)
get "/getpmtservicelang" $ do
lang <- param "lang"
txtPack' <- liftAndCatchIO $ run (findLangComponent lang "pmtservice")
case cast' . Doc =<< txtPack' of
Nothing -> status noContent204
Just textPack -> do
status ok200
Web.Scotty.json $ toJSON (textPack :: LangComponent)
get "/api/getlang" $ do get "/api/getlang" $ do
component <- param "component" component <- param "component"
lang <- param "lang" lang <- param "lang"
@ -1251,36 +1556,10 @@ listTxs user pwd a confs = do
Just e -> return $ Left $ "Error reading transactions: " <> emessage e Just e -> return $ Left $ "Error reading transactions: " <> emessage e
Left ex -> return $ Left $ (T.pack . show) ex Left ex -> return $ Left $ (T.pack . show) ex
-- | Function to check the ZGo full node for new txs
scanZcash :: Config -> Pipe -> IO ()
scanZcash config pipe = do
myTxs <-
listTxs (c_nodeUser config) (c_nodePwd config) (c_nodeAddress config) 1
case myTxs of
Right txs -> do
let r =
mkRegex
".*ZGO::([0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12})\\sReply-To:\\s(zs[a-z0-9]{76}).*"
let p =
mkRegex
".*ZGOp::([0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}).*"
let y =
mkRegex
".*MSG\\s(zs[a-z0-9]{76})\\s+ZGO::([0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12}).*"
let k = map zToZGoTx (filter (isRelevant r) txs)
mapM_ (access pipe master (c_dbName config) . upsertZGoTx "txs") k
let j = map zToZGoTx (filter (isRelevant p) txs)
mapM_ (upsertPayment pipe (c_dbName config)) j
let l = map zToZGoTx (filter (isRelevant y) txs)
mapM_ (access pipe master (c_dbName config) . upsertZGoTx "txs") l
Left e -> do
putStrLn $ "Error scanning node transactions: " ++ T.unpack e
return ()
-- | Function to filter transactions -- | Function to filter transactions
isRelevant :: Text.Regex.Regex -> ZcashTx -> Bool isRelevant :: Integer -> Text.Regex.Regex -> ZcashTx -> Bool
isRelevant re t isRelevant conf re t
| zconfirmations t < 100 && (matchTest re . T.unpack . zmemo) t = True | zconfirmations t < conf && (matchTest re . T.unpack . zmemo) t = True
| otherwise = False | otherwise = False
-- | New function to scan transactions with parser -- | New function to scan transactions with parser
@ -1296,19 +1575,24 @@ scanZcash' config pipe = do
-- | Function to scan loaded viewing keys for payments -- | Function to scan loaded viewing keys for payments
scanPayments :: Config -> Pipe -> IO () scanPayments :: Config -> Pipe -> IO ()
scanPayments config pipe = do scanPayments config pipe = do
shops <- listAddresses (c_nodeUser config) (c_nodePwd config) shopRecords <- access pipe master (c_dbName config) findActiveOwners
mapM_ (findPaidOrders config pipe) shops case shopRecords of
where [] -> return ()
findPaidOrders :: Config -> Pipe -> ZcashAddress -> IO () _ -> do
let shops = cast' . Doc <$> shopRecords :: [Maybe Owner]
let validShopAddresses = map (maybe "" oaddress) $ filter isJust shops
mapM_ (findPaidOrders config pipe) validShopAddresses
where findPaidOrders :: Config -> Pipe -> T.Text -> IO ()
findPaidOrders c p z = do findPaidOrders c p z = do
paidTxs <- listTxs (c_nodeUser c) (c_nodePwd c) (addy z) 5 print z
paidTxs <- listTxs (c_nodeUser c) (c_nodePwd c) z 5
case paidTxs of case paidTxs of
Right txs -> do Right txs -> do
let r = mkRegex ".*ZGo Order::([0-9a-fA-F]{24}).*" let r = mkRegex ".*ZGo Order::([0-9a-fA-F]{24}).*"
let k = filter (isRelevant r) txs let k = filter (isRelevant (c_confirmations c) r) txs
print k
let j = map (getOrderId r) k let j = map (getOrderId r) k
mapM_ (recordPayment p (c_dbName config)) j mapM_ (recordPayment p (c_dbName config) z) j
mapM_ (access p master (c_dbName config) . markOrderPaid) j
Left e -> print e Left e -> print e
getOrderId :: Text.Regex.Regex -> ZcashTx -> (String, Double) getOrderId :: Text.Regex.Regex -> ZcashTx -> (String, Double)
getOrderId re t = do getOrderId re t = do
@ -1316,16 +1600,17 @@ scanPayments config pipe = do
if not (null reg) if not (null reg)
then (fst $ head reg ! 1, zamount t) then (fst $ head reg ! 1, zamount t)
else ("", 0) else ("", 0)
recordPayment :: Pipe -> T.Text -> (String, Double) -> IO () recordPayment ::
recordPayment p dbName x = do Pipe -> T.Text -> T.Text -> (String, Double) -> IO ()
recordPayment p dbName z x = do
print x
o <- access p master dbName $ findOrderById (fst x) o <- access p master dbName $ findOrderById (fst x)
let xOrder = o >>= (cast' . Doc) let xOrder = o >>= (cast' . Doc)
case xOrder of case xOrder of
Nothing -> error "Failed to retrieve order from database" Nothing -> error "Failed to retrieve order from database"
Just xO -> Just xO ->
when when
(not (qpaid xO) && (not (qpaid xO) && qtotalZec xO == snd x && z == qaddress xO) $ do
qexternalInvoice xO /= "" && qtotalZec xO == snd x) $ do
let sReg = mkRegex "(.*)-([a-fA-f0-9]{24})" let sReg = mkRegex "(.*)-([a-fA-f0-9]{24})"
let sResult = matchAllText sReg (T.unpack $ qsession xO) let sResult = matchAllText sReg (T.unpack $ qsession xO)
if not (null sResult) if not (null sResult)
@ -1336,7 +1621,12 @@ scanPayments config pipe = do
case xC of case xC of
Nothing -> error "Failed to read Xero config" Nothing -> error "Failed to read Xero config"
Just xConf -> do Just xConf -> do
requestXeroToken p dbName xConf "" (qaddress xO) requestXeroToken
p
dbName
xConf
""
(qaddress xO)
payXeroInvoice payXeroInvoice
p p
dbName dbName
@ -1344,13 +1634,17 @@ scanPayments config pipe = do
(qaddress xO) (qaddress xO)
(qtotal xO) (qtotal xO)
(qtotalZec xO) (qtotalZec xO)
liftIO $
access p master dbName $ markOrderPaid x
"WC" -> do "WC" -> do
let wOwner = fst $ head sResult ! 2 let wOwner = fst $ head sResult ! 2
wooT <- wooT <-
access p master dbName $ findWooToken (read wOwner) access p master dbName $
findWooToken $ Just (read wOwner)
let wT = wooT >>= (cast' . Doc) let wT = wooT >>= (cast' . Doc)
case wT of case wT of
Nothing -> error "Failed to read WooCommerce token" Nothing ->
error "Failed to read WooCommerce token"
Just wt -> do Just wt -> do
let iReg = mkRegex "(.*)-(.*)-.*" let iReg = mkRegex "(.*)-(.*)-.*"
let iResult = let iResult =
@ -1371,10 +1665,13 @@ scanPayments config pipe = do
(C.pack . T.unpack $ w_token wt) (C.pack . T.unpack $ w_token wt)
(C.pack . show $ qprice xO) (C.pack . show $ qprice xO)
(C.pack . show $ qtotalZec xO) (C.pack . show $ qtotalZec xO)
liftIO $
access p master dbName $
markOrderPaid x
else error else error
"Couldn't parse externalInvoice for WooCommerce" "Couldn't parse externalInvoice for WooCommerce"
_ -> putStrLn "Not an integration order" _ -> putStrLn "Not an integration order"
else putStrLn "Not an integration order" else liftIO $ access p master dbName $ markOrderPaid x
-- | RPC methods -- | RPC methods
-- | List addresses with viewing keys loaded -- | List addresses with viewing keys loaded
@ -1537,4 +1834,17 @@ expireProSessions pipe db = do
access pipe master db $ removePro (psaddress z) access pipe master db $ removePro (psaddress z)
access pipe master db $ closeProSession z access pipe master db $ closeProSession z
checkUser ::
(Action IO (Maybe Document) -> IO (Maybe Document))
-> T.Text
-> IO (Maybe User)
checkUser run s = do
user <- run (findUser s)
return $ cast' . Doc =<< user
generateToken :: IO String
generateToken = do
rngState <- newCryptoRNGState
runCryptoRNGT rngState $ randomString 24 "abcdef0123456789"
debug = flip trace debug = flip trace

View file

@ -119,7 +119,6 @@ type Parser = Parsec Void T.Text
pSession :: Parser MemoToken pSession :: Parser MemoToken
pSession = do pSession = do
optional spaceChar
string "ZGO" string "ZGO"
pay <- optional $ char 'p' pay <- optional $ char 'p'
string "::" string "::"
@ -142,13 +141,18 @@ pSaplingAddress = do
pMsg :: Parser MemoToken pMsg :: Parser MemoToken
pMsg = do pMsg = do
Msg . T.pack <$> msg <-
some (alphaNumChar <|> punctuationChar <|> charCategory OtherSymbol) some
(alphaNumChar <|> punctuationChar <|> symbolChar <|>
charCategory OtherSymbol)
pure $ Msg . T.pack $ msg
pMemo :: Parser MemoToken pMemo :: Parser MemoToken
pMemo = do pMemo = do
optional spaceChar optional $ some spaceChar
pSession <|> pSaplingAddress <|> pMsg t <- pSession <|> pSaplingAddress <|> pMsg
optional $ some spaceChar
return t
isMemoToken :: T.Text -> MemoToken -> Bool isMemoToken :: T.Text -> MemoToken -> Bool
isMemoToken kind t = isMemoToken kind t =

View file

@ -17,7 +17,7 @@
# #
# resolver: ./custom-snapshot.yaml # resolver: ./custom-snapshot.yaml
# resolver: https://example.com/snapshots/2018-01-01.yaml # resolver: https://example.com/snapshots/2018-01-01.yaml
resolver: lts-20.19 resolver: lts-20.23
#url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/4.yaml #url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/4.yaml
# User packages to be built. # User packages to be built.
@ -44,6 +44,16 @@ packages:
extra-deps: extra-deps:
- git: https://github.com/reach-sh/haskell-hexstring.git - git: https://github.com/reach-sh/haskell-hexstring.git
commit: 085c16fb21b9f856a435a3faab980e7e0b319341 commit: 085c16fb21b9f856a435a3faab980e7e0b319341
- git: https://git.vergara.tech/Vergara_Tech/zcash-haskell.git
commit: fef3d3af35a09db718cddb8fc9166b2d2691a744
- git: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
commit: 787c2e813eb3a5d16c375d4b37dfefbd2adcdf05
- git: https://github.com/well-typed/borsh.git
commit: d2fcfa159e0a844b1ec5e8ed3e232d4b380fa831
- aeson-2.1.2.1@sha256:5b8d62a60963a925c4d123a46e42a8e235a32188522c9f119f64ac228c2612a7,6359
- vector-0.13.0.0@sha256:fa5cac81a17a5af388716792e8b99c24b3b66770086756d0d8b23f8272a0244c,9112
- generically-0.1.1
- vector-algorithms-0.9.0.1
- blake3-0.2@sha256:d1146b9a51ccfbb0532780778b6d016a614e3d44c05d8c1923dde9a8be869045,2448 - blake3-0.2@sha256:d1146b9a51ccfbb0532780778b6d016a614e3d44c05d8c1923dde9a8be869045,2448
- crypto-rng-0.3.0.1@sha256:04f4ae75943ecad8b794950985054130f272d65a588b6b6528f56df0bfedc4dc,1565 - crypto-rng-0.3.0.1@sha256:04f4ae75943ecad8b794950985054130f272d65a588b6b6528f56df0bfedc4dc,1565
# Override default flag values for local packages and extra-deps # Override default flag values for local packages and extra-deps

View file

@ -15,6 +15,67 @@ packages:
original: original:
commit: 085c16fb21b9f856a435a3faab980e7e0b319341 commit: 085c16fb21b9f856a435a3faab980e7e0b319341
git: https://github.com/reach-sh/haskell-hexstring.git git: https://github.com/reach-sh/haskell-hexstring.git
- completed:
commit: fef3d3af35a09db718cddb8fc9166b2d2691a744
git: https://git.vergara.tech/Vergara_Tech/zcash-haskell.git
name: zcash-haskell
pantry-tree:
sha256: ec7782cf2646da17548d59af0ea98dcbaac1b6c2176258c696a7f508db6dbc21
size: 1126
version: 0.1.0
original:
commit: fef3d3af35a09db718cddb8fc9166b2d2691a744
git: https://git.vergara.tech/Vergara_Tech/zcash-haskell.git
- completed:
commit: 787c2e813eb3a5d16c375d4b37dfefbd2adcdf05
git: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
name: foreign-rust
pantry-tree:
sha256: be2f6fc0fab58a90fec657bdb6bd0ccf0810c7dccfe95c78b85e174fae227e42
size: 2315
version: 0.1.0
original:
commit: 787c2e813eb3a5d16c375d4b37dfefbd2adcdf05
git: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
- completed:
commit: d2fcfa159e0a844b1ec5e8ed3e232d4b380fa831
git: https://github.com/well-typed/borsh.git
name: borsh
pantry-tree:
sha256: 8335925f495a5a653fcb74b6b8bb18cd0b6b7fe7099a1686108704e6ab82f47b
size: 2268
version: 0.3.0
original:
commit: d2fcfa159e0a844b1ec5e8ed3e232d4b380fa831
git: https://github.com/well-typed/borsh.git
- completed:
hackage: aeson-2.1.2.1@sha256:5b8d62a60963a925c4d123a46e42a8e235a32188522c9f119f64ac228c2612a7,6359
pantry-tree:
sha256: 58d33beedd6e0ff79920c636d8a4295deb684b6e97c9b1ca94d3c780958d6302
size: 82465
original:
hackage: aeson-2.1.2.1@sha256:5b8d62a60963a925c4d123a46e42a8e235a32188522c9f119f64ac228c2612a7,6359
- completed:
hackage: vector-0.13.0.0@sha256:fa5cac81a17a5af388716792e8b99c24b3b66770086756d0d8b23f8272a0244c,9112
pantry-tree:
sha256: d2461d28022c8c0a91da08b579b1bff478f617102d2f5ef596cc5b28d14b8b6a
size: 4092
original:
hackage: vector-0.13.0.0@sha256:fa5cac81a17a5af388716792e8b99c24b3b66770086756d0d8b23f8272a0244c,9112
- completed:
hackage: generically-0.1.1@sha256:2b9b5efb6eea2fb65377565d53d85b0ccc5b37404fba4bef1d60277caa877e5e,1155
pantry-tree:
sha256: 98a8fe89d516d3752a9cc0af22cfa652f098cc6613da080762b63aa1d596e56d
size: 233
original:
hackage: generically-0.1.1
- completed:
hackage: vector-algorithms-0.9.0.1@sha256:f3e5c6695529a94edf762117cafd91c989cb642ad3f8ca4014dbb13c8f6c2a20,3826
pantry-tree:
sha256: aef389e57ae6020e5da719bee40aaf6cccf1c4d1e7743a85d30c9d8c25d170a0
size: 1510
original:
hackage: vector-algorithms-0.9.0.1
- completed: - completed:
hackage: blake3-0.2@sha256:d1146b9a51ccfbb0532780778b6d016a614e3d44c05d8c1923dde9a8be869045,2448 hackage: blake3-0.2@sha256:d1146b9a51ccfbb0532780778b6d016a614e3d44c05d8c1923dde9a8be869045,2448
pantry-tree: pantry-tree:
@ -31,7 +92,7 @@ packages:
hackage: crypto-rng-0.3.0.1@sha256:04f4ae75943ecad8b794950985054130f272d65a588b6b6528f56df0bfedc4dc,1565 hackage: crypto-rng-0.3.0.1@sha256:04f4ae75943ecad8b794950985054130f272d65a588b6b6528f56df0bfedc4dc,1565
snapshots: snapshots:
- completed: - completed:
sha256: 42f77c84b34f68c30c2cd0bf8c349f617a0f428264362426290847a6a2019b64 sha256: 4c972e067bae16b95961dbfdd12e07f1ee6c8fffabbfa05c3d65100b03f548b7
size: 649618 size: 650253
url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/19.yaml url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/23.yaml
original: lts-20.19 original: lts-20.23

View file

@ -13,10 +13,12 @@ import Data.Either
import Data.Maybe import Data.Maybe
import Data.SecureMem import Data.SecureMem
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Time import Data.Time
import Data.Time.Calendar import Data.Time.Calendar
import Data.Time.Clock import Data.Time.Clock
import Data.Time.Clock.POSIX import Data.Time.Clock.POSIX
import qualified Data.UUID as U
import Database.MongoDB import Database.MongoDB
import Item import Item
import LangComponent import LangComponent
@ -32,6 +34,7 @@ import Test.Hspec.QuickCheck
import Test.QuickCheck import Test.QuickCheck
import Test.QuickCheck.Gen import Test.QuickCheck.Gen
import Test.QuickCheck.Monadic import Test.QuickCheck.Monadic
import Text.Megaparsec
import User import User
import Web.Scotty import Web.Scotty
import WooCommerce import WooCommerce
@ -53,7 +56,31 @@ main = do
describe "hex strings" $ do describe "hex strings" $ do
prop "encoding and decoding are inverse" $ \x -> prop "encoding and decoding are inverse" $ \x ->
(decodeHexText . encodeHexText) x == x (decodeHexText . encodeHexText) x == x
describe "zToZGoTx" $ do describe "zToZGoTx" $
--prop "memo parsing" testMemoParser
do
it "parse ZecWallet memo" $ do
let m =
runParser
pZGoMemo
"Zecwalllet memo"
"ZGO::5d3d4494-51c0-432d-8495-050419957aea\nReply-To:\nzs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
case m of
Left e -> putStrLn $ errorBundlePretty e
Right m' ->
m_session m' `shouldBe`
U.fromString "5d3d4494-51c0-432d-8495-050419957aea"
it "parse YWallet memo" $ do
let m =
runParser
pZGoMemo
"Ywallet memo"
"\128737MSG\nzs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e\n\nZGO::ad8477d3-4fdd-4c97-90b2-76630b5f77e1"
case m of
Left e -> putStrLn $ errorBundlePretty e
Right m' ->
m_session m' `shouldBe`
U.fromString "ad8477d3-4fdd-4c97-90b2-76630b5f77e1"
it "converts ZecWallet tx to ZGo tx" $ do it "converts ZecWallet tx to ZGo tx" $ do
let t = let t =
ZcashTx ZcashTx
@ -156,32 +183,13 @@ main = do
getResponseStatus res `shouldBe` accepted202 getResponseStatus res `shouldBe` accepted202
describe "Price endpoint" $ do describe "Price endpoint" $ do
it "returns a price for an existing currency" $ do it "returns a price for an existing currency" $ do
req <- req <- testGet "/price" [("currency", Just "usd")]
testGet
"/api/price"
[ ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")
, ("currency", Just "usd")
]
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200 getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "returns 204 when the currency is not supported" $ do it "returns 204 when the currency is not supported" $ do
req <- req <- testGet "/price" [("currency", Just "jpy")]
testGet
"/api/price"
[ ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")
, ("currency", Just "jpy")
]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` noContent204 getResponseStatus res `shouldBe` noContent204
it "returs 401 when the session is not valid" $ do
req <-
testGet
"/api/price"
[ ("session", Just "th7s1sa-fake-6u1d-7h47-1m4deuph3r3")
, ("currency", Just "usd")
]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
describe "Countries endpoint" $ do describe "Countries endpoint" $ do
it "returns a list of countries" $ do it "returns a list of countries" $ do
req <- req <-
@ -201,7 +209,7 @@ main = do
it "returns a block number" $ do it "returns a block number" $ do
req <- req <-
testGet testGet
"/api/blockheight" "/blockheight"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpJSON req res <- httpJSON req
height (getResponseBody (res :: Response Block)) `shouldSatisfy` \x -> height (getResponseBody (res :: Response Block)) `shouldSatisfy` \x ->
@ -225,18 +233,32 @@ main = do
req <- req <-
testGet testGet
"/api/xeroaccount" "/api/xeroaccount"
[ ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd") [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
, ("address", Just "Zaddy")
]
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200 getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "returns 401 with invalid session" $ do it "reading returns 401 with invalid session" $ do
req <- req <-
testGet testGet
"/api/xeroaccount" "/api/xeroaccount"
[("session", Just "fnelrkgnlyebrlvns82949")] [("session", Just "fnelrkgnlyebrlvns82949")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401 getResponseStatus res `shouldBe` unauthorized401
it "setting returns 401 with invalid session" $ do
req <-
testPost
"/api/xeroaccount"
[("session", Just "fnelrkgnlyebrlvns82949")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
it "setting succeeds with valid session" $ do
req <-
testPost
"/api/xeroaccount"
[ ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")
, ("code", Just "ZEC")
]
res <- httpLBS req
getResponseStatus res `shouldBe` accepted202
describe "User endpoint" $ do describe "User endpoint" $ do
it "returns a user for a session" $ do it "returns a user for a session" $ do
req <- req <-
@ -252,12 +274,37 @@ main = do
[("session", Just "suchafak-euui-dican-eve-nbelieveitca")] [("session", Just "suchafak-euui-dican-eve-nbelieveitca")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401 getResponseStatus res `shouldBe` unauthorized401
describe "delete" $ do
it "returns 401 when session is invalid" $ do
req <-
testDelete
"/api/user/"
"6272a90f2b05a74cf1000005"
[("session", Just "suchafak-euui-dican-eve-nbelieveitca")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
it "returns 403 when user and session don't match" $ do
req <-
testDelete
"/api/user/"
"6272a90f2b05a74cf1000005"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` forbidden403
it "returns 400 when user is invalid" $ do
req <-
testDelete
"/api/user/"
"000000000000000000000000"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` badRequest400
it "deletes user by id" $ do it "deletes user by id" $ do
req <- req <-
testDelete testDelete
"/api/user/" "/api/user/"
"6272a90f2b05a74cf1000003" "6272a90f2b05a74cf1000003"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdaa")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` ok200 getResponseStatus res `shouldBe` ok200
describe "Owner endpoint" $ describe "Owner endpoint" $
@ -294,8 +341,90 @@ main = do
] ]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` ok200 getResponseStatus res `shouldBe` ok200
describe "Order endpoints" $ do describe "Order endpoints" $
prop "upsert order" testOrderAdd --prop "upsert order" testOrderAdd
do
it "adding order with bad session fails with 401" $ do
myTs <- liftIO getCurrentTime
let testOrder =
ZGoOrder
(Just (read "627ab3ea2b05a76be3000011"))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd"
myTs
False
"usd"
102.0
0
0
[]
False
""
""
"testToken4321"
req <-
testPostJson "/api/order" $
A.object ["payload" A..= A.toJSON testOrder]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-fake-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` unauthorized401
it "adding order with mismatched session fails with 403" $ do
myTs <- liftIO getCurrentTime
let testOrder =
ZGoOrder
(Just (read "627ab3ea2b05a76be3000011"))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd"
myTs
False
"usd"
102.0
0
0
[]
False
""
""
"testToken4321"
req <-
testPostJson "/api/order" $
A.object ["payload" A..= A.toJSON testOrder]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dfake")]
req
getResponseStatus res `shouldBe` forbidden403
it "adding order with correct session succeeds" $ do
myTs <- liftIO getCurrentTime
let testOrder =
ZGoOrder
(Just (read "627ab3ea2b05a76be3000011"))
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd"
myTs
False
"usd"
102.0
0
0
[]
False
""
""
"testToken4321"
req <-
testPostJson "/api/order" $
A.object ["payload" A..= A.toJSON testOrder]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` created201
it "get order by session" $ do it "get order by session" $ do
req <- req <-
testGet testGet
@ -303,7 +432,7 @@ main = do
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200 getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "get order by session fails when invalid" $ do it "get order by session fails with bad session" $ do
req <- req <-
testGet testGet
"/api/order" "/api/order"
@ -313,40 +442,49 @@ main = do
it "get order by id" $ do it "get order by id" $ do
req <- req <-
testGet testGet
"/api/order/627ab3ea2b05a76be3000000" "/order/627ab3ea2b05a76be3000000"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("token", Just "testToken1234")]
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200 getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "get order with wrong id" $ do it "get order with invalid id fails with 400" $ do
req <- testGet "/order/6273hrb" [("token", Just "testToken1234")]
res <- httpLBS req
getResponseStatus res `shouldBe` badRequest400
it "get order by id fails with bad token" $ do
req <- req <-
testGet testGet
"/api/order/6273hrb" "/order/627ab3ea2b05a76be3000000"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("token", Just "wrongToken1234")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` noContent204 getResponseStatus res `shouldBe` forbidden403
it "get order by id fails with bad session" $ do
req <-
testGet
"/api/order/627ab3ea2b05a76be3000000"
[("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
it "get all orders for owner" $ do it "get all orders for owner" $ do
req <- req <-
testGet testGet
"/api/allorders" "/api/allorders"
[ ("address", Just "Zaddy") [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
, ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")
]
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200 getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "get all orders for owner fails with bad session" $ do it "get all orders for owner fails with bad session" $ do
req <- req <-
testGet testGet
"/api/allorders" "/api/allorders"
[ ("address", Just "Zaddy") [("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
, ("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd") res <- httpLBS req
] getResponseStatus res `shouldBe` unauthorized401
it "delete order by id fails with mismatched session" $ do
req <-
testDelete
"/api/order/"
"627ab3ea2b05a76be3000000"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dfake")]
res <- httpLBS req
getResponseStatus res `shouldBe` forbidden403
it "delete order by id fails with bad session" $ do
req <-
testDelete
"/api/order/"
"627ab3ea2b05a76be3000000"
[("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401 getResponseStatus res `shouldBe` unauthorized401
it "delete order by id" $ do it "delete order by id" $ do
@ -357,35 +495,98 @@ main = do
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` ok200 getResponseStatus res `shouldBe` ok200
it "delete order by id fails with bad session" $ do
req <-
testDelete
"/api/order/"
"627ab3ea2b05a76be3000000"
[("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
describe "Item endpoint" $ do describe "Item endpoint" $ do
prop "add item" testItemAdd it "adding item with bad session fails" $ do
it "get items" $ do let item =
Item
Nothing
"Table"
"Oak"
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
499.99
req <-
testPostJson "/api/item" $ A.object ["payload" A..= A.toJSON item]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-fake-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` unauthorized401
it "adding item with good session succeeds" $ do
let item =
Item
(Just (read "627d7ba92b05a76be3000013"))
"Table"
"Oak"
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
499.99
req <-
testPostJson "/api/item" $ A.object ["payload" A..= A.toJSON item]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` created201
it "get items with valid session succeeds" $ do
req <- req <-
testGet testGet
"/api/items" "/api/items"
[ ("address", Just "Zaddy") [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
, ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")
]
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200 getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "delete item" $ do it "get items with invalid session returns 401" $ do
req <-
testGet
"/api/items"
[("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
describe "delete item" $ do
it "returns 401 with invalid session and item ID" $ do
req <-
testDelete
"/api/item/"
"627d7ba92b05a76be3000003"
[("session", Just "35bfb9c2-9ad2-fake-adda-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
it "returns 403 when item ID doesn't belong to session" $ do
req <- req <-
testDelete testDelete
"/api/item/" "/api/item/"
"627d7ba92b05a76be3000003" "627d7ba92b05a76be3000003"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] [("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` forbidden403
it "succeeds with valid session and item ID" $ do
req <-
testDelete
"/api/item/"
"627d7ba92b05a76be3000013"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` ok200 getResponseStatus res `shouldBe` ok200
describe "WooCommerce endpoints" $ do describe "WooCommerce endpoints" $ do
it "generate token" $ do it "generate token with invalid session gives 401" $ do
req <-
testPost
"/api/wootoken"
[ ("ownerid", Just "627ad3492b05a76be3000001")
, ("session", Just "35bfb9c2-9ad2-fake-adda-99d63b8dcdcd")
]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
it "generate token with mismatched session gives 403" $ do
req <-
testPost
"/api/wootoken"
[ ("ownerid", Just "627ad3492b05a76be3000001")
, ("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dfake")
]
res <- httpLBS req
getResponseStatus res `shouldBe` forbidden403
it "generate token with valid session succeeds" $ do
req <- req <-
testPost testPost
"/api/wootoken" "/api/wootoken"
@ -394,6 +595,20 @@ main = do
] ]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` accepted202 getResponseStatus res `shouldBe` accepted202
it "read token gives 401 with bad session" $ do
req <-
testGet
"/api/wootoken"
[("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
res <- httpLBS req
getResponseStatus res `shouldBe` unauthorized401
it "read token succeeds with valid session" $ do
req <-
testGet
"/api/wootoken"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` ok200
it "authenticate with incorrect owner" $ do it "authenticate with incorrect owner" $ do
req <- req <-
testPublicGet testPublicGet
@ -417,13 +632,17 @@ main = do
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` accepted202 getResponseStatus (res :: Response A.Value) `shouldBe` accepted202
it "authenticate with correct token" $ do it "authenticate with correct token" $ do
req1 <-
testGet
"/api/wootoken"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res1 <- httpJSON req1
let tk = getResponseBody (res1 :: Response WooToken)
req <- req <-
testPublicGet testPublicGet
"/auth" "/auth"
[ ("ownerid", Just "627ad3492b05a76be3000001") [ ("ownerid", Just "627ad3492b05a76be3000001")
, ( "token" , ("token", Just $ (E.encodeUtf8 . w_token) tk)
, Just
"0c1702c16c7bd7e075b8bb129b24888a5cc2181fa1eb4ce9190cfcb625ecf0ee")
, ("siteurl", Just "aHR0cHM6Ly93d3cudGVjcHJvdmFsLmNvbS8") , ("siteurl", Just "aHR0cHM6Ly93d3cudGVjcHJvdmFsLmNvbS8")
] ]
res <- httpJSON req res <- httpJSON req
@ -441,13 +660,17 @@ main = do
res <- httpJSON req res <- httpJSON req
getResponseStatus (res :: Response A.Value) `shouldBe` accepted202 getResponseStatus (res :: Response A.Value) `shouldBe` accepted202
it "request order creation" $ do it "request order creation" $ do
req1 <-
testGet
"/api/wootoken"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res1 <- httpJSON req1
let tk = getResponseBody (res1 :: Response WooToken)
req <- req <-
testPublicGet testPublicGet
"/woopayment" "/woopayment"
[ ("ownerid", Just "627ad3492b05a76be3000001") [ ("ownerid", Just "627ad3492b05a76be3000001")
, ( "token" , ("token", Just $ (E.encodeUtf8 . w_token) tk)
, Just
"0c1702c16c7bd7e075b8bb129b24888a5cc2181fa1eb4ce9190cfcb625ecf0ee")
, ("siteurl", Just "aHR0cHM6Ly93d3cudGVjcHJvdmFsLmNvbS8") , ("siteurl", Just "aHR0cHM6Ly93d3cudGVjcHJvdmFsLmNvbS8")
, ("order_id", Just "1234") , ("order_id", Just "1234")
, ("currency", Just "usd") , ("currency", Just "usd")
@ -498,6 +721,63 @@ main = do
] ]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` noContent204 getResponseStatus res `shouldBe` noContent204
describe "Viewing Key endpoint" $ do
let vk0 =
"zxviews1qwrw0jlxqqqqpqr9faepwqpgj09f0ee55mfwl60eumv6duk5pwncntweah0xdlhqrwre2fgmgersah9atx92z6pmxec8t32mpz59t47yuplkcdcaw3873aalv7e59xhwv846g9q9qjy0ypc68ceypg6pux490dr4snsc4m482l57rvnzj2lsh4f3dv6mltc75z72pypkx0dchwpumdwfuajstfhwulv30kjt5l0x7juwe523ufwz2xleplxf37gk2pfh59gmdjr4zsql4ga9p"
let vk1 =
"zxviews1qdjagrrpqqqqpq8es75mlu6rref0qyrstchf8dxzeygtsejwfqu8ckhwl2qj5m8am7lmupxk3vkvdjm8pawjpmesjfapvsqw96pa46c2z0kk7letrxf7mkltwz54fwpxc7kc79mm5kce3rwn5ssl009zwsra2spppwgrx25s9k5hq65f69l4jz2tjmqgy0pl49qmtaj3nudk6wglwe2hpa327hydlchtyq9av6wjd6hu68e04ahwk9a9n2kt0kj3nj99nue65awtu5cwwcpjs"
let vk2 =
"zxviews1qdjagrrpqqqqpq8es75mlufakef0qyrstchf8dxzeygtsejwfqu8ckhwl2qj5m8am7lmupxk3vkvdjm8pawjpmesjfapvsqw96pa46c2z0kk7letrxf7mkltwz54fwpxc7kc79mm5kce3rwn5ssl009zwsra2spppwgrx25s9k5hq65f69l4jz2tjmqgy0pl49qmtaj3nudk6wglwe2hpa327hydlchtyq9av6wjd6hu68e04ahwk9a9n2kt0kj3nj99nue65awtu5cwwcpjs"
it "returns 401 with bad session" $ do
req <-
testPostJson "/api/ownervk" $
A.object ["payload" A..= (vk0 :: String)]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` unauthorized401
it "returns 403 with mismatched session" $ do
req <-
testPostJson "/api/ownervk" $
A.object ["payload" A..= (vk0 :: String)]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` forbidden403
it "returns 400 with malformed key" $ do
req <-
testPostJson "/api/ownervk" $
A.object ["payload" A..= (vk2 :: String)]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` badRequest400
it "returns 400 with non-key valid bech32" $ do
req <-
testPostJson "/api/ownervk" $
A.object ["payload" A..= ("bech321qqqsyrhqy2a" :: String)]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` badRequest400
it "succeeds with correct key" $ do
req <-
testPostJson "/api/ownervk" $
A.object ["payload" A..= (vk1 :: String)]
res <-
httpLBS $
setRequestQueryString
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
req
getResponseStatus res `shouldBe` created201
around handleDb $ around handleDb $
describe "Database actions" $ do describe "Database actions" $ do
describe "authentication" $ do describe "authentication" $ do
@ -512,7 +792,7 @@ main = do
doc <- doc <-
access p master "test" $ access p master "test" $
findProSession findProSession
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
doc `shouldNotBe` Nothing doc `shouldNotBe` Nothing
it "upsert to DB" $ const pending it "upsert to DB" $ const pending
describe "Zcash prices" $ do describe "Zcash prices" $ do
@ -573,7 +853,7 @@ main = do
let myOrder = let myOrder =
ZGoOrder ZGoOrder
(Just (read "627ab3ea2b05a76be3000001")) (Just (read "627ab3ea2b05a76be3000001"))
"Zaddy" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd" "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd"
myTs myTs
False False
@ -585,6 +865,7 @@ main = do
False False
"" ""
"" ""
"testToken1234"
let ordTest = val myOrder let ordTest = val myOrder
case ordTest of case ordTest of
Doc oT -> access p master "test" (insert_ "orders" oT) Doc oT -> access p master "test" (insert_ "orders" oT)
@ -600,25 +881,26 @@ main = do
Just o2 -> qpaid o2 `shouldBe` True Just o2 -> qpaid o2 `shouldBe` True
describe "Xero data" $ do describe "Xero data" $ do
it "token is saved" $ \p -> do it "token is saved" $ \p -> do
let myToken = t <-
XeroToken access p master "test" $
Nothing findToken
"Zaddy" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"superFakeToken123"
1800
"anotherSuperFakeToken"
(UTCTime (fromGregorian 2022 9 16) (secondsToDiffTime 0))
(UTCTime (fromGregorian 2022 9 16) (secondsToDiffTime 0))
""
_ <- access p master "test" $ upsertToken myToken
t <- access p master "test" $ findToken "Zaddy"
let t1 = (cast' . Doc) =<< t let t1 = (cast' . Doc) =<< t
case t1 of case t1 of
Nothing -> True `shouldBe` False Nothing -> True `shouldBe` False
Just t2 -> t_address t2 `shouldBe` "Zaddy" Just t2 ->
t_address t2 `shouldBe`
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
it "code is saved" $ \p -> do it "code is saved" $ \p -> do
_ <- access p master "test" $ addAccCode "Zaddy" "ZEC" _ <-
t <- access p master "test" $ findToken "Zaddy" access p master "test" $
addAccCode
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"ZEC"
t <-
access p master "test" $
findToken
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
let t1 = (cast' . Doc) =<< t let t1 = (cast' . Doc) =<< t
case t1 of case t1 of
Nothing -> True `shouldBe` False Nothing -> True `shouldBe` False
@ -650,7 +932,7 @@ main = do
let myUser = let myUser =
User User
(Just (read "6272a90f2b05a74cf1000002" :: ObjectId)) (Just (read "6272a90f2b05a74cf1000002" :: ObjectId))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcb" "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcb"
1613487 1613487
"1234567" "1234567"
@ -692,13 +974,13 @@ main = do
findOne findOne
(select (select
[ "address" =: [ "address" =:
("zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" :: T.Text) ("zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4" :: T.Text)
] ]
"owners") "owners")
let s = (cast' . Doc) =<< t let s = (cast' . Doc) =<< t
let ownerPaid = maybe False opaid s let ownerPaid = maybe False opaid s
ownerPaid `shouldBe` True ownerPaid `shouldBe` True
_ -> True `shouldBe` False `debug` "Failed parsing payment" _ -> True `shouldBe` False --`debug` "Failed parsing payment"
xit "owners are expired" $ \p -> do xit "owners are expired" $ \p -> do
_ <- expireOwners p "test" _ <- expireOwners p "test"
now <- getCurrentTime now <- getCurrentTime
@ -717,7 +999,7 @@ main = do
let myTx = let myTx =
ZGoTx ZGoTx
Nothing Nothing
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca" "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca"
3 3
1613487 1613487
@ -800,6 +1082,23 @@ testDelete endpoint par body = do
setRequestPath (B.append endpoint par) defaultRequest setRequestPath (B.append endpoint par) defaultRequest
return testRequest return testRequest
testMemoParser :: T.Text -> T.Text -> T.Text -> Property
testMemoParser t1 t2 t3 =
monadicIO $ do
let res =
runParser pZGoMemo "Parser test" $
t1 <>
" zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e " <>
t2 <> " ZGO::5d3d4494-51c0-432d-8495-050419957aea " <> t3
case res of
Left e -> assert False `debug` errorBundlePretty e
Right zm ->
assert $
U.fromString "5d3d4494-51c0-432d-8495-050419957aea" == m_session zm &&
Just
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" ==
m_address zm
testOwnerAdd :: Owner -> Property testOwnerAdd :: Owner -> Property
testOwnerAdd o = testOwnerAdd o =
monadicIO $ do monadicIO $ do
@ -848,6 +1147,14 @@ closeDbConnection = close
handleDb :: (Pipe -> Expectation) -> IO () handleDb :: (Pipe -> Expectation) -> IO ()
handleDb = bracket openDbConnection closeDbConnection handleDb = bracket openDbConnection closeDbConnection
filterDocs :: Value -> Bool
filterDocs (Doc v) = True
filterDocs _ = False
unwrapDoc :: Value -> Document
unwrapDoc (Doc v) = v
unwrapDoc _ = []
startAPI :: Config -> IO () startAPI :: Config -> IO ()
startAPI config = do startAPI config = do
putStrLn "Starting test server ..." putStrLn "Starting test server ..."
@ -860,54 +1167,39 @@ startAPI config = do
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "users")) _ <- access pipe master "test" (Database.MongoDB.delete (select [] "users"))
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "items")) _ <- access pipe master "test" (Database.MongoDB.delete (select [] "items"))
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "orders")) _ <- access pipe master "test" (Database.MongoDB.delete (select [] "orders"))
_ <-
access pipe master "test" (Database.MongoDB.delete (select [] "xerotokens"))
let myUser = let myUser =
User User
(Just (read "6272a90f2b05a74cf1000001" :: ObjectId)) (Just (read "6272a90f2b05a74cf1000001" :: ObjectId))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd" "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd"
1613487 1613487
"8ea140fbb30615d6cae383c4f62f3ad9afb10b804f63138d5b53990bd56e0162" "8ea140fbb30615d6cae383c4f62f3ad9afb10b804f63138d5b53990bd56e0162"
False False
_ <-
access
pipe
master
"test"
(insert_
"users"
[ "address" =: uaddress myUser
, "_id" =: u_id myUser
, "session" =: usession myUser
, "blocktime" =: ublocktime myUser
, "pin" =: upin myUser
, "validated" =: uvalidated myUser
])
let myUser1 = let myUser1 =
User User
(Just (read "6272a90f2b05a74cf1000003" :: ObjectId)) (Just (read "6272a90f2b05a74cf1000003" :: ObjectId))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd" "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdaa"
1613487 1613487
"8ea140fbb30615d6cae383c4f62f3ad9afb10b804f63138d5b53990bd56e0162" "8ea140fbb30615d6cae383c4f62f3ad9afb10b804f63138d5b53990bd56e0162"
True True
_ <- let myUser2 =
access User
pipe (Just (read "6272a90f2b05a74cf1000005" :: ObjectId))
master "zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3fake"
"test" "35bfb9c2-9ad2-4fe5-adda-99d63b8dfake"
(insert_ 1613487
"users" "8ea140fbb30615d6cae383c4f62f3ad9afb10b804f63138d5b53990bd56e0162"
[ "address" =: uaddress myUser1 True
, "_id" =: u_id myUser1 let userList =
, "session" =: usession myUser1 map unwrapDoc $ filter filterDocs $ val <$> [myUser, myUser1, myUser2]
, "blocktime" =: ublocktime myUser1 _ <- access pipe master "test" (insertAll_ "users" userList)
, "pin" =: upin myUser1
, "validated" =: uvalidated myUser1
])
let myOwner = let myOwner =
Owner Owner
(Just (read "627ad3492b05a76be3000001")) (Just (read "627ad3492b05a76be3000001"))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"Test shop" "Test shop"
"usd" "usd"
False False
@ -931,17 +1223,48 @@ startAPI config = do
False False
"" ""
"" ""
let myOwner1 =
Owner
(Just (read "627ad3492b05a76be3000008"))
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3fake"
"Test shop 2"
"usd"
False
0
False
0
"Roxy"
"Foo"
"roxy@zgo.cash"
"1 Main St"
"Mpls"
"Minnesota"
"55401"
""
"missyfoo.io"
"United States"
True
False
False
(UTCTime (fromGregorian 2023 8 6) (secondsToDiffTime 0))
False
""
""
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "owners")) _ <- access pipe master "test" (Database.MongoDB.delete (select [] "owners"))
let o = val myOwner let o = val myOwner
case o of case o of
Doc d -> access pipe master "test" (insert_ "owners" d) Doc d -> access pipe master "test" (insert_ "owners" d)
_ -> fail "Couldn't save Owner in DB" _ -> fail "Couldn't save Owner in DB"
let o1 = val myOwner1
case o1 of
Doc d1 -> access pipe master "test" (insert_ "owners" d1)
_ -> fail "Couldn't save Owner1 in DB"
_ <- access pipe master "test" (Database.MongoDB.delete (select [] "orders")) _ <- access pipe master "test" (Database.MongoDB.delete (select [] "orders"))
myTs <- liftIO getCurrentTime myTs <- liftIO getCurrentTime
let myOrder = let myOrder =
ZGoOrder ZGoOrder
(Just (read "627ab3ea2b05a76be3000000")) (Just (read "627ab3ea2b05a76be3000000"))
"Zaddy" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd" "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd"
myTs myTs
False False
@ -953,6 +1276,7 @@ startAPI config = do
False False
"" ""
"" ""
"testToken1234"
let ordTest = val myOrder let ordTest = val myOrder
case ordTest of case ordTest of
Doc oT -> access pipe master "test" (insert_ "orders" oT) Doc oT -> access pipe master "test" (insert_ "orders" oT)
@ -971,13 +1295,24 @@ startAPI config = do
let proSession1 = let proSession1 =
ZGoProSession ZGoProSession
Nothing Nothing
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e" "zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
myTs myTs
False False
let proSessionTest = val proSession1 let proSessionTest = val proSession1
case proSessionTest of case proSessionTest of
Doc pS1 -> access pipe master "test" (insert_ "prosessions" pS1) Doc pS1 -> access pipe master "test" (insert_ "prosessions" pS1)
_ -> fail "Couldn't save test ZGoProSession in DB" _ -> fail "Couldn't save test ZGoProSession in DB"
let myToken =
XeroToken
Nothing
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
"superFakeToken123"
1800
"anotherSuperFakeToken"
(UTCTime (fromGregorian 2022 9 16) (secondsToDiffTime 0))
(UTCTime (fromGregorian 2022 9 16) (secondsToDiffTime 0))
""
_ <- access pipe master "test" $ upsertToken myToken
--let myWooToken = --let myWooToken =
--WooToken --WooToken
--Nothing --Nothing
@ -1006,7 +1341,8 @@ instance Arbitrary ZGoOrder where
l <- arbitrary l <- arbitrary
pd <- arbitrary pd <- arbitrary
eI <- arbitrary eI <- arbitrary
ZGoOrder i a s ts c cur p t tZ l pd eI <$> arbitrary sc <- arbitrary
ZGoOrder i a s ts c cur p t tZ l pd eI sc <$> arbitrary
instance Arbitrary LineItem where instance Arbitrary LineItem where
arbitrary = do arbitrary = do

View file

@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
name: zgo-backend name: zgo-backend
version: 1.5.0 version: 1.6.0
synopsis: Haskell Back-end for the ZGo point-of-sale application synopsis: Haskell Back-end for the ZGo point-of-sale application
description: Please see the README at <https://git.vergara.tech/Vergara_Tech//zgo-backend#readme> description: Please see the README at <https://git.vergara.tech/Vergara_Tech//zgo-backend#readme>
category: Web category: Web
@ -78,6 +78,7 @@ library
, wai-cors , wai-cors
, wai-extra , wai-extra
, warp-tls , warp-tls
, zcash-haskell
default-language: Haskell2010 default-language: Haskell2010
executable zgo-backend-exe executable zgo-backend-exe
@ -175,10 +176,13 @@ test-suite zgo-backend-test
, hspec-wai , hspec-wai
, http-conduit , http-conduit
, http-types , http-types
, megaparsec
, mongoDB , mongoDB
, scotty , scotty
, securemem , securemem
, text , text
, time , time
, uuid
, zcash-haskell
, zgo-backend , zgo-backend
default-language: Haskell2010 default-language: Haskell2010

View file

@ -6,6 +6,7 @@ dbUser = "zgo"
dbPassword = "zcashrules" dbPassword = "zcashrules"
nodeUser = "zecwallet" nodeUser = "zecwallet"
nodePassword = "rdsxlun6v4a" nodePassword = "rdsxlun6v4a"
confirmations = 100
port = 3000 port = 3000
tls = false tls = false
certificate = "/path/to/cert.pem" certificate = "/path/to/cert.pem"

View file

@ -6,6 +6,7 @@ dbUser = "zgo"
dbPassword = "zcashrules" dbPassword = "zcashrules"
nodeUser = "zecwallet" nodeUser = "zecwallet"
nodePassword = "rdsxlun6v4a" nodePassword = "rdsxlun6v4a"
confirmations = 100
port = 3000 port = 3000
tls = false tls = false
certificate = "/path/to/cert.pem" certificate = "/path/to/cert.pem"