Implement user creation and PINs

This commit is contained in:
Rene Vergara 2022-05-03 08:59:29 -05:00
parent 3acaa7e487
commit 71450efc2e
Signed by: pitmutt
GPG key ID: 65122AD495A7F5B2
5 changed files with 80 additions and 35 deletions

View file

@ -3,19 +3,9 @@
module Main where module Main where
import Control.Concurrent (forkIO, threadDelay) import Control.Concurrent (forkIO, threadDelay)
import Control.Monad
import Control.Monad.IO.Class
import Data.Aeson
import qualified Data.ByteString as B
import Data.SecureMem import Data.SecureMem
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Lazy as L
import Database.MongoDB import Database.MongoDB
import GHC.Generics
import Network.HTTP.Simple
import Network.HTTP.Types.Status
import Network.Wai.Middleware.HttpAuth
import Web.Scotty
import ZGoBackend import ZGoBackend
passkey :: SecureMem passkey :: SecureMem

View file

@ -54,6 +54,7 @@ executables:
- -threaded - -threaded
- -rtsopts - -rtsopts
- -with-rtsopts=-N - -with-rtsopts=-N
- -Wall
dependencies: dependencies:
- zgo-backend - zgo-backend
- base - base

View file

@ -14,12 +14,14 @@ import qualified Data.Bson as B
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import Data.Char import Data.Char
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
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.Lazy as L import qualified Data.Text.Lazy as L
import Data.Time.Clock import Data.Time.Clock
import qualified Data.Vector as V import qualified Data.Vector as V
import Database.MongoDB import Database.MongoDB
import Debug.Trace
import GHC.Generics import GHC.Generics
import Network.HTTP.Simple import Network.HTTP.Simple
import Network.HTTP.Types.Status import Network.HTTP.Types.Status
@ -187,12 +189,12 @@ parseCountryBson d = do
-- | Type to represent a ZGo User, i.e.: a specific device -- | Type to represent a ZGo User, i.e.: a specific device
data User = data User =
User User
{ _id :: String { u_id :: String
, address :: T.Text , uaddress :: T.Text
, session :: T.Text , usession :: T.Text
, blocktime :: Integer , ublocktime :: Integer
, pin :: T.Text , upin :: T.Text
, validated :: Bool , uvalidated :: Bool
} }
deriving (Eq, Show, Generic, ToJSON) deriving (Eq, Show, Generic, ToJSON)
@ -281,7 +283,7 @@ data ZGoPrice =
{ _id :: String { _id :: String
, currency :: T.Text , currency :: T.Text
, price :: Double , price :: Double
, timestamp :: String , timestamp :: UTCTime
} }
deriving (Eq, Show, Generic, ToJSON) deriving (Eq, Show, Generic, ToJSON)
@ -291,7 +293,7 @@ parseZGoPrice d = do
c <- B.lookup "currency" d c <- B.lookup "currency" d
p <- B.lookup "price" d p <- B.lookup "price" d
t <- B.lookup "timestamp" d t <- B.lookup "timestamp" d
pure $ ZGoPrice (show (i :: B.ObjectId)) c p (show (t :: B.Value)) pure $ ZGoPrice (show (i :: B.ObjectId)) c p t
-- | Type for the CoinGecko response -- | Type for the CoinGecko response
newtype CoinGeckoPrices = newtype CoinGeckoPrices =
@ -314,20 +316,25 @@ findUser :: T.Text -> Action IO (Maybe Document)
findUser s = findOne (select ["session" =: s] "users") findUser s = findOne (select ["session" =: s] "users")
-- | Function to create user from ZGoTx -- | Function to create user from ZGoTx
addUser :: T.Text -> ZGoTx -> Action IO () addUser :: Pipe -> T.Text -> T.Text -> Maybe ZGoTx -> Action IO ()
addUser node (ZGoTx i a s c bt am t m) = do addUser _ _ _ Nothing = return () --`debug` "addUser got Nothing"
addUser p db node (Just tx) = do
isNew <- liftIO $ isUserNew p db tx
if isNew
then do
let newPin = unsafePerformIO generatePin let newPin = unsafePerformIO generatePin
let msg = sendPin node a newPin _ <- sendPin node (address tx) newPin
insert_ insert_
"users" "users"
[ "address" =: a [ "address" =: address tx
, "session" =: s , "session" =: session tx
, "blocktime" =: bt , "blocktime" =: blocktime tx
, "pin" =: newPin , "pin" =: newPin
, "validated" =: False , "validated" =: False
] ]
else return ()
sendPin :: T.Text -> T.Text -> T.Text -> IO () sendPin :: T.Text -> T.Text -> T.Text -> Action IO String
sendPin nodeAddress addr pin = do sendPin nodeAddress addr pin = do
let payload = let payload =
[ Data.Aeson.String nodeAddress [ Data.Aeson.String nodeAddress
@ -336,15 +343,15 @@ sendPin nodeAddress addr pin = do
[ object [ object
[ "address" .= addr [ "address" .= addr
, "amount" .= (0.00000001 :: Double) , "amount" .= (0.00000001 :: Double)
, "memo" .= pin , "memo" .= encodeHexText ("ZGo PIN: " ++ T.unpack (pin))
] ]
]) ])
] ]
r <- makeZcashCall "z_sendmany" payload r <- makeZcashCall "z_sendmany" payload
let sCode = getResponseStatus (r :: Response Object) let sCode = getResponseStatus (r :: Response Object)
if sCode == ok200 if sCode == ok200
then putStrLn "Pin sent!" then return "Pin sent!"
else putStrLn "Pin sending failed :(" else return "Pin sending failed :("
-- | Function to query DB for transactions with less than 10 confirmations -- | Function to query DB for transactions with less than 10 confirmations
findPending :: String -> Action IO [Document] findPending :: String -> Action IO [Document]
@ -509,11 +516,13 @@ getZcashPrices = do
setRequestPath "/api/v3/simple/price" defaultRequest setRequestPath "/api/v3/simple/price" defaultRequest
httpJSON priceRequest httpJSON priceRequest
-- | Function to update the Zcash prices in the ZGo db
checkZcashPrices :: Pipe -> T.Text -> IO () checkZcashPrices :: Pipe -> T.Text -> IO ()
checkZcashPrices p db = do checkZcashPrices p db = do
q <- getZcashPrices q <- getZcashPrices
mapM_ (access p master db) (updatePrices (getResponseBody q)) mapM_ (access p master db) (updatePrices (getResponseBody q))
-- | Function to check the ZGo full node for new txs
scanZcash :: T.Text -> Pipe -> T.Text -> IO () scanZcash :: T.Text -> Pipe -> T.Text -> IO ()
scanZcash addr pipe db = do scanZcash addr pipe db = do
r <- makeZcashCall "z_listreceivedbyaddress" [Data.Aeson.String addr] r <- makeZcashCall "z_listreceivedbyaddress" [Data.Aeson.String addr]
@ -530,3 +539,25 @@ scanZcash addr pipe db = do
mapM_ (access pipe master db . upsertZGoTx "txs") k mapM_ (access pipe master db . upsertZGoTx "txs") k
let j = map zToZGoTx (filter (matchTest p . T.unpack . zmemo) txs) let j = map zToZGoTx (filter (matchTest p . T.unpack . zmemo) txs)
mapM_ (access pipe master db . upsertZGoTx "payments") j mapM_ (access pipe master db . upsertZGoTx "payments") j
-- | Function to generate users from login txs
updateLogins :: T.Text -> Pipe -> T.Text -> IO ()
updateLogins addr pipe db = do
results <-
access
pipe
master
db
(rest =<<
find (select ["confirmations" =: ["$lt" =: (100 :: Integer)]] "txs"))
let parsed = map parseZGoTxBson results
mapM_ (access pipe master db . ZGoBackend.addUser pipe db addr) parsed
putStrLn "Updated logins!"
isUserNew :: Pipe -> T.Text -> ZGoTx -> IO Bool
isUserNew p db tx = do
res <-
(access p master db (findOne (select ["session" =: (session tx)] "users")))
return $ isNothing res
debug = flip trace

View file

@ -166,6 +166,29 @@ main =
case s of case s of
Nothing -> True `shouldBe` False Nothing -> True `shouldBe` False
Just z -> confirmations z `shouldSatisfy` (> 0) Just z -> confirmations z `shouldSatisfy` (> 0)
it "login txs are converted to users" $ \p -> do
let myTx =
ZGoTx
""
"zs1w6nkameazc5gujm69350syl5w8tgvyaphums3pw8eytzy5ym08x7dvskmykkatmwrucmgv3er8e"
"35bfb9c2-9ad2-4fe5-adda-99d63b8dcdca"
3
1613487
0.00000001
"abcdef"
"Super Memo"
_ <- access p master "test" (delete (select [] "users"))
_ <- access p master "test" (insert_ "txs" (encodeZGoTxBson myTx))
_ <- updateLogins nodeAddress p "test"
threadDelay 1000000
t <- access p master "test" $ findOne (select [] "users")
case t of
Nothing -> True `shouldBe` False
Just r -> do
let s = parseUserBson r
case s of
Nothing -> True `shouldBe` False
Just z -> length (T.unpack (usession z)) `shouldSatisfy` (> 0)
testGet :: B.ByteString -> [(B.ByteString, Maybe B.ByteString)] -> IO Request testGet :: B.ByteString -> [(B.ByteString, Maybe B.ByteString)] -> IO Request
testGet endpoint body = do testGet endpoint body = do

View file

@ -59,7 +59,7 @@ executable zgo-backend-exe
Paths_zgo_backend Paths_zgo_backend
hs-source-dirs: hs-source-dirs:
app app
ghc-options: -threaded -rtsopts -with-rtsopts=-N ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
build-depends: build-depends:
aeson aeson
, base , base