Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save billsbooth/63361e21244d46d3dfa341de632ce837 to your computer and use it in GitHub Desktop.
Save billsbooth/63361e21244d46d3dfa341de632ce837 to your computer and use it in GitHub Desktop.
Backend Sign In Request
const IdentityTokenHeader = "Privy-Id-Token"
// PART 1
// PUBLIC API
func siwp(c wrappers.WriteApiContext) {
// Get the privy jwt token from the request cookies
privyJwtToken := c.GetHeader(IdentityTokenHeader)
if privyJwtToken == "" {
apierror.ErrResponse(c, apierror.NewBadRequestErr("Missing privy-id-token"))
return
}
refCode := c.Query("ref_code")
if refCode == "" {
// Place holder ref code.
refCode = "tomcat"
}
privyClient, err := apictx.GetPrivyClient(c)
if err != nil {
apierror.ErrResponse(c, err)
return
}
validateJwtRes, err := privyClient.ValidateJwtToken(privyJwtToken)
if err != nil {
apierror.ErrResponse(c, apierror.NewBadRequestWrappedErr(err, "Invalid jwt token"))
return
}
if validateJwtRes.EmailLinkedAccount == nil || validateJwtRes.EmailLinkedAccount.Address == "" {
apierror.ErrResponse(c, apierror.NewBadRequestErr("Email info not found on account"))
return
}
store, err := apictx.GetStore(c)
if err != nil {
apierror.ErrResponse(c, err)
return
}
authSvc, err := apictx.GetAuthService(c)
if err != nil {
apierror.ErrResponse(c, err)
return
}
account, getErr := store.AccountsV2().GetByPrivyId(c, validateJwtRes.PrivyUserId)
var ok bool
if ferror.IsNotFound(getErr) {
account, ok = doSignupV3(
c,
store,
authSvc,
validateJwtRes.PrivyUserId,
validateJwtRes.EmailLinkedAccount.Address,
pggenadapter.BlockchainPlatformSolana,
refCode,
)
if !ok {
// Error is handled in doSignupV3
return
}
} else if getErr != nil {
apierror.ErrResponse(c, getErr)
return
}
err = authmiddleware.SetSessionV2Key(c, account.Id)
if err != nil {
apierror.ErrResponse(c, err)
return
}
res := LoginResponse{AccountAddress: account.Address}
result := rest.Result[LoginResponse]{ // nolint:exhaustruct // All fields not needed here
Success: true,
Result: res,
}
c.JSON(http.StatusOK, result)
}
// PART 2
// SIGN UP FLOW
func doSignupV3(
c wrappers.WriteApiContext,
store state.ReadStore,
authSvc auth.Service,
privyUserId string,
email string,
platform pggenadapter.BlockchainPlatform,
refCode string,
) (accounts_v2.AccountV2, bool) {
// nolint:exhaustruct
z := accounts_v2.AccountV2{}
accountService, err := apictx.GetAccountService(c)
if err != nil {
apierror.ErrResponse(c, err)
//nolint:exhaustruct
return z, false
}
referralCodeReadService, err := apictx.GetReferralCodeReadService(c)
if err != nil {
apierror.ErrResponse(c, err)
return z, false
}
referralCodeWriteService, err := apictx.GetReferralCodeWriteService(c)
if err != nil {
apierror.ErrResponse(c, err)
return z, false
}
ts := futils.Now()
// Validate the referral code
referralCode, getReferralCodeErr := referralCodeReadService.GetReferralCodeByCode(c, store, refCode)
if ferror.IsNotFound(getReferralCodeErr) {
apierror.ErrResponse(c, apierror.NewBadRequestErr("Invalid referral code."))
return z, false
} else if getReferralCodeErr != nil {
apierror.ErrResponse(c, getReferralCodeErr)
return z, false
}
if !referralCode.Unlimited && referralCode.Claimed > 0 {
apierror.ErrResponse(c, apierror.NewBadRequestErr("Referral code is already used"))
return z, false
}
accountId, err := accountIdGenerator.Get()()
if err != nil {
apierror.ErrResponse(c, ferror.Wrap(err, "unable to create account id"))
return z, false
}
var wallet server_wallets.ServerWallet
switch platform {
case enums.BlockchainPlatformSolana:
var err error
wallet, err = authSvc.CreateSolanaWallet(accountId)
if err != nil {
apierror.ErrResponse(c, ferror.Wrap(err, "unable to create wallet"))
return z, false
}
default:
apierror.ErrResponse(c, apierror.NewBadRequestErr("Unsupported platform"))
return z, false
}
var account accounts_v2.AccountV2
var createAccountErr error
writeErr := store.Write(c, statelog.InputTypeSiwpCreateAccoount, func(stx state.WriteStore) error {
account, createAccountErr = accountService.CreateAccountV2(
stx,
platform,
wallet.Address,
nil,
nil,
nullable.ToPtr(email),
nullable.ToPtr(privyUserId),
ts,
nullable.ToPtr(accountId),
)
if createAccountErr != nil {
return createAccountErr
}
_, err = stx.ServerWallets().Upsert(wallet)
if err != nil {
return ferror.Wrap(err, "unable to upsert server wallet")
}
claimErr := referralCodeWriteService.ClaimReferralCodeTx(stx, referralCode.Id, account.Id, ts)
if claimErr != nil {
return claimErr
}
_, createRefErr := referralCodeWriteService.CreateReferralCodesTx(stx, &account.Id, nil, nil, AccountCreationRefCodes, false, ts)
if createRefErr != nil {
return createRefErr
}
return nil
})
if writeErr != nil {
apierror.ErrResponse(c, writeErr)
return z, false
}
return account, true
}
var accountIdGenerator = concurrency.NewField(func() (uuid.UUID, error) {
return uuid.NewRandom()
})
// Part 3:
// Setting the cookie
// "github.com/gorilla/sessions"
func SetSessionV2Key(c wrappers.ReadApiContext, accountID uuid.UUID) error {
session := c.SessionsDefaultMany(SessionKeyV2)
session.Set(SessionKeyV2, accountID.String())
if err := session.Save(); err != nil {
return ferror.Wrap(err, "unable to save session")
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment