Merge branch 'security1'

This commit is contained in:
Rene Vergara 2023-06-26 11:28:33 -05:00
commit ea731df20d
Signed by: pitmutt
GPG key ID: 65122AD495A7F5B2
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,102 +628,288 @@ 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 Nothing -> status noContent204
Just x -> do Just c -> do
let xConfig = cast' (Doc x) case cast' . Doc =<< user of
case xConfig of Nothing -> status unauthorized401
Nothing -> status noContent204 Just u -> do
Just c -> 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)
, "shop" .= (Nothing :: Maybe String)
])
Just c -> do
o <- liftAndCatchIO $ run $ findOwnerById $ xr_owner invReq
case cast' . Doc =<< o of
Nothing -> do Nothing -> do
status noContent204 status ok200
text "Xero App credentials corrupted" Web.Scotty.json
Just c -> do (object
res <- [ "reportType" .= (2 :: Integer)
, "order" .= (Nothing :: Maybe ZGoOrder)
, "shop" .= (Nothing :: Maybe String)
])
Just o' -> do
existingOrder <-
liftAndCatchIO $ liftAndCatchIO $
requestXeroToken pipe (c_dbName config) c "none" oAddress run $
if res findXeroOrder
then do (oaddress o')
resInv <- (xr_invNo invReq)
(xr_shortCode invReq)
case cast' . Doc =<< existingOrder of
Nothing -> do
res <-
liftAndCatchIO $ liftAndCatchIO $
getXeroInvoice pipe (c_dbName config) inv oAddress requestXeroToken pipe (c_dbName config) c "none" $ oaddress o'
case resInv of if res
Nothing -> do then do
status noContent204 resInv <-
text "Xero invoice not found" liftAndCatchIO $
Just xI -> do getXeroInvoice pipe (c_dbName config) (xr_invNo invReq) $
oaddress o'
case resInv of
Nothing -> do
status ok200
Web.Scotty.json
(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 status ok200
Web.Scotty.json (object ["invdata" .= toJSON xI]) Web.Scotty.json
else status noContent204 (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)
let c = cast' . Doc =<< res case cast' . Doc =<< user of
case c of Nothing -> status unauthorized401
Nothing -> status noContent204 Just u -> do
Just c1 -> do res <- liftAndCatchIO $ run (findToken $ uaddress u)
status ok200 let c = cast' . Doc =<< res
Web.Scotty.json case c of
(object Nothing -> status noContent204
[ "message" .= ("Xero account code found" :: String) Just c1 -> do
, "code" .= t_code c1 status ok200
]) Web.Scotty.json
(object
[ "message" .= ("Xero account code found" :: String)
, "code" .= t_code c1
])
-- 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"
liftAndCatchIO $ run (addAccCode oAdd c) user <- liftAndCatchIO $ run (findUser session)
status accepted202 case cast' . Doc =<< user of
Nothing -> status unauthorized401
Just u -> do
let oAdd = uaddress u
liftAndCatchIO $ run (addAccCode oAdd c)
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)
let t1 = cast' . Doc =<< res case cast' . Doc =<< user of
case t1 of Nothing -> status unauthorized401
Nothing -> status noContent204 Just u -> do
Just t -> do owner <- liftAndCatchIO $ run (findOwner $ uaddress u)
status ok200 case cast' . Doc =<< owner of
Web.Scotty.json Nothing -> status internalServerError500
(object Just o -> do
[ "ownerid" .= show (w_owner t) res <- liftAndCatchIO $ run (findWooToken $ o_id o)
, "token" .= w_token t let t1 = cast' . Doc =<< res
, "siteurl" .= w_url t case t1 of
]) Nothing -> status noContent204
Just t -> do
status ok200
Web.Scotty.json
(object
[ "ownerid" .= show (w_owner t)
, "token" .= w_token t
, "siteurl" .= w_url t
])
post "/api/wootoken" $ do post "/api/wootoken" $ do
oid <- param "ownerid" oid <- param "ownerid"
res <- liftAndCatchIO $ run (findOwnerById oid) session <- param "session"
let o1 = cast' . Doc =<< res user <- liftAndCatchIO $ run (findUser session)
case o1 of case cast' . Doc =<< user of
Nothing -> status noContent204 Nothing -> status unauthorized401
Just o -> do Just u -> do
liftAndCatchIO $ run (generateWooToken o) res <- liftAndCatchIO $ run (findOwnerById oid)
status accepted202 case cast' . Doc =<< res of
Nothing -> status badRequest400
Just o -> do
if oaddress o == uaddress u
then do
tk <- liftIO generateToken
liftAndCatchIO $ run (generateWooToken o tk)
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 then do
liftAndCatchIO $ run (deleteUser userId) u <- liftAndCatchIO $ run (findUserById userId)
status ok200 case cast' . Doc =<< u of
else status noContent204 Nothing -> status badRequest400
Just u' ->
if session == usession u'
then do
liftAndCatchIO $ run (deleteUser userId)
status ok200
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,33 +1205,99 @@ 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 items of case cast' . Doc =<< user of
[] -> status noContent204 Nothing -> status forbidden403
_ -> do Just u -> do
let pItems = map (cast' . Doc) items :: [Maybe Item] items <- liftAndCatchIO $ run (findItems $ uaddress u)
status ok200 case items of
Web.Scotty.json [] -> status noContent204
(object _ -> do
["message" .= ("Items found!" :: String), "items" .= toJSON pItems]) let pItems = map (cast' . Doc) items :: [Maybe Item]
status ok200
Web.Scotty.json
(object
[ "message" .= ("Items found!" :: String)
, "items" .= toJSON pItems
])
--Upsert item --Upsert item
post "/api/item" $ do post "/api/item" $ do
i <- jsonData i <- jsonData
let q = payload (i :: Payload Item) session <- param "session"
_ <- liftAndCatchIO $ run (upsertItem q) user <- liftAndCatchIO $ run (findUser session)
status created201 case cast' . Doc =<< user of
Nothing -> status forbidden403
Just u -> do
let q = payload (i :: Payload Item)
if uaddress u == iowner q
then do
_ <- liftAndCatchIO $ run (upsertItem q)
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
then do Nothing -> status forbidden403
liftAndCatchIO $ run (deleteItem oId) Just u -> do
status ok200 i <- liftAndCatchIO $ run (findItemById oId)
else status noContent204 case cast' . Doc =<< i of
Nothing -> status badRequest400
Just i' -> do
if iowner i' == uaddress u
then do
liftAndCatchIO $ run (deleteItem oId)
status ok200
else status forbidden403
--Get price for Zcash --Get price for Zcash
get "/price" $ do get "/price" $ do
curr <- param "currency" curr <- param "currency"
@ -1057,39 +1313,48 @@ 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 myOrders of case cast' . Doc =<< user of
[] -> status noContent204 Nothing -> status unauthorized401
_ -> do Just u -> do
let pOrders = map (cast' . Doc) myOrders :: [Maybe ZGoOrder] myOrders <- liftAndCatchIO $ run (findAllOrders $ uaddress u)
status ok200 case myOrders of
Web.Scotty.json [] -> status noContent204
(object _ -> do
[ "message" .= ("Orders found!" :: String) let pOrders = map (cast' . Doc) myOrders :: [Maybe ZGoOrder]
, "orders" .= toJSON pOrders status ok200
]) Web.Scotty.json
(object
[ "message" .= ("Orders found!" :: String)
, "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 Just pOrder -> do
let o' = cast' (Doc o) if qtoken pOrder == token
case o' of then do
Nothing -> status internalServerError500 shop <- liftAndCatchIO $ run (findOwner $ qaddress pOrder)
Just pOrder -> do case cast' . Doc =<< shop of
status ok200 Nothing -> status badRequest400
Web.Scotty.json Just s -> do
(object status ok200
[ "message" .= ("Order found!" :: String) Web.Scotty.json
, "order" .= toJSON (pOrder :: ZGoOrder) (object
]) [ "message" .= ("Order found!" :: String)
else status noContent204 , "order" .= toJSON (pOrder :: ZGoOrder)
, "shop" .= (oname s :: T.Text)
])
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)
_ <- liftAndCatchIO $ run (upsertOrder q) session <- param "session"
status created201 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)
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"
liftAndCatchIO $ run (deleteOrder oId) session <- param "session"
status ok200 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)
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,85 +1575,103 @@ 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
findPaidOrders c p z = do let shops = cast' . Doc <$> shopRecords :: [Maybe Owner]
paidTxs <- listTxs (c_nodeUser c) (c_nodePwd c) (addy z) 5 let validShopAddresses = map (maybe "" oaddress) $ filter isJust shops
case paidTxs of mapM_ (findPaidOrders config pipe) validShopAddresses
Right txs -> do where findPaidOrders :: Config -> Pipe -> T.Text -> IO ()
let r = mkRegex ".*ZGo Order::([0-9a-fA-F]{24}).*" findPaidOrders c p z = do
let k = filter (isRelevant r) txs print z
let j = map (getOrderId r) k paidTxs <- listTxs (c_nodeUser c) (c_nodePwd c) z 5
mapM_ (recordPayment p (c_dbName config)) j case paidTxs of
mapM_ (access p master (c_dbName config) . markOrderPaid) j Right txs -> do
Left e -> print e let r = mkRegex ".*ZGo Order::([0-9a-fA-F]{24}).*"
getOrderId :: Text.Regex.Regex -> ZcashTx -> (String, Double) let k = filter (isRelevant (c_confirmations c) r) txs
getOrderId re t = do print k
let reg = matchAllText re (T.unpack $ zmemo t) let j = map (getOrderId r) k
if not (null reg) mapM_ (recordPayment p (c_dbName config) z) j
then (fst $ head reg ! 1, zamount t) Left e -> print e
else ("", 0) getOrderId :: Text.Regex.Regex -> ZcashTx -> (String, Double)
recordPayment :: Pipe -> T.Text -> (String, Double) -> IO () getOrderId re t = do
recordPayment p dbName x = do let reg = matchAllText re (T.unpack $ zmemo t)
o <- access p master dbName $ findOrderById (fst x) if not (null reg)
let xOrder = o >>= (cast' . Doc) then (fst $ head reg ! 1, zamount t)
case xOrder of else ("", 0)
Nothing -> error "Failed to retrieve order from database" recordPayment ::
Just xO -> Pipe -> T.Text -> T.Text -> (String, Double) -> IO ()
when recordPayment p dbName z x = do
(not (qpaid xO) && print x
qexternalInvoice xO /= "" && qtotalZec xO == snd x) $ do o <- access p master dbName $ findOrderById (fst x)
let sReg = mkRegex "(.*)-([a-fA-f0-9]{24})" let xOrder = o >>= (cast' . Doc)
let sResult = matchAllText sReg (T.unpack $ qsession xO) case xOrder of
if not (null sResult) Nothing -> error "Failed to retrieve order from database"
then case fst $ head sResult ! 1 of Just xO ->
"Xero" -> do when
xeroConfig <- access p master dbName findXero (not (qpaid xO) && qtotalZec xO == snd x && z == qaddress xO) $ do
let xC = xeroConfig >>= (cast' . Doc) let sReg = mkRegex "(.*)-([a-fA-f0-9]{24})"
case xC of let sResult = matchAllText sReg (T.unpack $ qsession xO)
Nothing -> error "Failed to read Xero config" if not (null sResult)
Just xConf -> do then case fst $ head sResult ! 1 of
requestXeroToken p dbName xConf "" (qaddress xO) "Xero" -> do
payXeroInvoice xeroConfig <- access p master dbName findXero
p let xC = xeroConfig >>= (cast' . Doc)
dbName case xC of
(qexternalInvoice xO) Nothing -> error "Failed to read Xero config"
(qaddress xO) Just xConf -> do
(qtotal xO) requestXeroToken
(qtotalZec xO) p
"WC" -> do dbName
let wOwner = fst $ head sResult ! 2 xConf
wooT <- ""
access p master dbName $ findWooToken (read wOwner) (qaddress xO)
let wT = wooT >>= (cast' . Doc) payXeroInvoice
case wT of p
Nothing -> error "Failed to read WooCommerce token" dbName
Just wt -> do (qexternalInvoice xO)
let iReg = mkRegex "(.*)-(.*)-.*" (qaddress xO)
let iResult = (qtotal xO)
matchAllText (qtotalZec xO)
iReg liftIO $
(T.unpack $ qexternalInvoice xO) access p master dbName $ markOrderPaid x
if not (null iResult) "WC" -> do
then do let wOwner = fst $ head sResult ! 2
let wUrl = wooT <-
E.decodeUtf8With lenientDecode . access p master dbName $
B64.decodeLenient . C.pack $ findWooToken $ Just (read wOwner)
fst $ head iResult ! 1 let wT = wooT >>= (cast' . Doc)
let iNum = fst $ head iResult ! 2 case wT of
payWooOrder Nothing ->
(T.unpack wUrl) error "Failed to read WooCommerce token"
(C.pack iNum) Just wt -> do
(C.pack $ maybe "" show (q_id xO)) let iReg = mkRegex "(.*)-(.*)-.*"
(C.pack . T.unpack $ w_token wt) let iResult =
(C.pack . show $ qprice xO) matchAllText
(C.pack . show $ qtotalZec xO) iReg
else error (T.unpack $ qexternalInvoice xO)
"Couldn't parse externalInvoice for WooCommerce" if not (null iResult)
_ -> putStrLn "Not an integration order" then do
else putStrLn "Not an integration order" let wUrl =
E.decodeUtf8With lenientDecode .
B64.decodeLenient . C.pack $
fst $ head iResult ! 1
let iNum = fst $ head iResult ! 2
payWooOrder
(T.unpack wUrl)
(C.pack iNum)
(C.pack $ maybe "" show (q_id xO))
(C.pack . T.unpack $ w_token wt)
(C.pack . show $ qprice xO)
(C.pack . show $ qtotalZec xO)
liftIO $
access p master dbName $
markOrderPaid x
else error
"Couldn't parse externalInvoice for WooCommerce"
_ -> 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,14 +274,39 @@ 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
it "deletes user by id" $ do describe "delete" $ do
req <- it "returns 401 when session is invalid" $ do
testDelete req <-
"/api/user/" testDelete
"6272a90f2b05a74cf1000003" "/api/user/"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")] "6272a90f2b05a74cf1000005"
res <- httpLBS req [("session", Just "suchafak-euui-dican-eve-nbelieveitca")]
getResponseStatus res `shouldBe` ok200 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
req <-
testDelete
"/api/user/"
"6272a90f2b05a74cf1000003"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdaa")]
res <- httpLBS req
getResponseStatus res `shouldBe` ok200
describe "Owner endpoint" $ describe "Owner endpoint" $
--prop "add owner" testOwnerAdd --prop "add owner" testOwnerAdd
do do
@ -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 <- req <-
testDelete testGet
"/api/item/" "/api/items"
"627d7ba92b05a76be3000003" [("session", Just "35bfb9c2-9ad2-4fe5-fake-99d63b8dcdcd")]
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
res <- httpLBS req res <- httpLBS req
getResponseStatus res `shouldBe` ok200 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 <-
testDelete
"/api/item/"
"627d7ba92b05a76be3000003"
[("session", Just "35bfb9c2-9ad2-4fe5-adda-99d63b8dcdcd")]
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
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"