Skip to content

Commit

Permalink
Merge pull request #51 from CudoVentures/CUDOS-1866-firebase-auth-cus…
Browse files Browse the repository at this point in the history
…tom-tokens

CUDOS-1866 implement firebase wallet auth
  • Loading branch information
maptuhec authored Dec 6, 2022
2 parents 50e8a22 + 58352c5 commit 975f47b
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 72 deletions.
12 changes: 6 additions & 6 deletions example.env.file
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ VITE_APP_STAKING_URL='http://localhost:3000/validators'
VITE_APP_CHAIN_NAME="CudosTestnet-Local"
VITE_APP_CHAIN_ID="cudos-local-network"
VITE_APP_GAS_PRICE="5000000000000"
VITE_APP_FIREBASE_API_KEY="AddressBook123"
VITE_APP_FIREBASE_AUTH_DOMAIN="address-book-123.firebaseapp.com"
VITE_APP_FIREBASE_PROJECT_ID="address-book-123"
VITE_APP_FIREBASE_AUTH_EMAIL="[email protected]"
VITE_APP_FIREBASE_AUTH_PASSWORD="123123"
VITE_APP_FIREBASE_COLLECTION_NAME="address-book"
VITE_APP_FIREBASE_API_KEY="Exampl3envf1l3"
VITE_APP_FIREBASE_PROJECT_ID="example-project-id"
VITE_APP_FIREBASE_DOMAIN="example-project-id.firebaseapp.com"
VITE_APP_FIREBASE_ADDRESS_BOOK_COLLECTION="example-address-book"
VITE_APP_FIREBASE_AUTH_NONCE_URL="https://example-firebase.com/getNonce"
VITE_APP_FIREBASE_AUTH_VERIFY_URL="https://example-firebase.com/verifySignedNonceMsg"
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"axios": "^0.27.2",
"bignumber.js": "^9.0.2",
"csstype": "^3.0.10",
"cudosjs": "^1.1.0",
"cudosjs": "^1.2.1",
"firebase": "^9.9.1",
"goober": "^2.1.1",
"graphql": "^16.5.0",
Expand Down
20 changes: 20 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ import { COSMOSTATION_LEDGER, KEPLR_LEDGER } from 'utils/constants'
import { connectUser } from 'utils/config'
import { initialState as initialUserState } from 'store/user'
import { updateModalState } from 'store/modals'
import { auth, getAddressBook } from 'utils/firebase'
import { signInWithCustomToken } from 'firebase/auth'

const App = () => {
const location = useLocation()
const apolloClient = useApollo(null)
const themeColor = useSelector((state: RootState) => state.settings.theme)
const { firebaseToken, address } = useSelector((state: RootState) => state.userState);
const dispatch = useDispatch()

const connectAccount = useCallback(async (ledgerType: string) => {
Expand Down Expand Up @@ -70,6 +73,23 @@ const App = () => {

}, [connectAccount])

useEffect(() => {
if (firebaseToken) {
signInWithCustomToken(auth, firebaseToken!).catch(e => console.error(e));
}
}, [firebaseToken])

useEffect(() => {
if (firebaseToken) {
const fetchAddressBook = async () => {
const addressBook = await getAddressBook(address!);
dispatch(updateUser({ addressBook }));
};

fetchAddressBook().catch(e => console.error(e));
}
}, [firebaseToken])

return (
<Container maxWidth='xl' style={{ display: 'contents', height: '100vh', width: '100vw', overflow: 'auto' }}>
<ApolloProvider client={apolloClient}>
Expand Down
26 changes: 13 additions & 13 deletions src/components/Dialog/AddressBook/AddAddressButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { RootState } from 'store'
import { initialState as initialModalState } from 'store/modals'
import { CSVLink } from "react-csv"
import { HtmlTooltip } from 'utils/multiSendTableHelper'
import { Firebase } from 'utils/firebase'
import { saveAddressBook } from 'utils/firebase'
import { getConnectedUserAddressAndName } from 'utils/config'

import {
Expand Down Expand Up @@ -83,10 +83,9 @@ const AddAddressButtons = () => {
message: FILE_ERROR_MSG
}))
} else {
dispatch(updateUser({ addressBook: txBatch }))

const { address } = await getConnectedUserAddressAndName(connectedLedger!)
await Firebase.saveAddressBook(address, txBatch);
await saveAddressBook(address, txBatch);
dispatch(updateUser({ addressBook: txBatch }));
}
}

Expand Down Expand Up @@ -114,15 +113,16 @@ const AddAddressButtons = () => {
}

if (!fail) {
const newAddressBook = { ...addressBook, [userAddress]: userName }
const newAddressBook = { ...addressBook, [userAddress]: userName };
const { address } = await getConnectedUserAddressAndName(connectedLedger!)

await saveAddressBook(address, newAddressBook);

dispatch(updateUser({
addressBook: newAddressBook,
newAddedAddress: userAddress
}))

const { address } = await getConnectedUserAddressAndName(connectedLedger!)
await Firebase.saveAddressBook(address, newAddressBook);

localStorage.removeItem('addressBookAccountName')
localStorage.removeItem('addressBookAccountAddress')
dispatch(updateModalState({ addNewAddress: false }))
Expand Down Expand Up @@ -164,13 +164,13 @@ const AddAddressButtons = () => {
...updatedAddressBook,
[newRecord.address]: newRecord.name
}
dispatch(updateUser({
addressBook: newAddressBook
}))
dispatch(updateModalState({ editAddressBookRecord: false }))

const { address } = await getConnectedUserAddressAndName(connectedLedger!)
await Firebase.saveAddressBook(address, newAddressBook);
await saveAddressBook(address, newAddressBook);

dispatch(updateUser({ addressBook: newAddressBook }))

dispatch(updateModalState({ editAddressBookRecord: false }))

return
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Dialog/AddressBook/AddressBookTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import copy from 'copy-to-clipboard'
import { formatAddress } from 'utils/helpers';
import { updateUser } from 'store/user';
import { updateModalState } from 'store/modals';
import { Firebase } from 'utils/firebase'
import { saveAddressBook } from 'utils/firebase'
import { getConnectedUserAddressAndName } from 'utils/config'

import {
Expand Down Expand Up @@ -166,7 +166,7 @@ export default function AddressBookTable() {
}

const { address } = await getConnectedUserAddressAndName(connectedLedger!)
await Firebase.saveAddressBook(address, newAddressBook);
await saveAddressBook(address, newAddressBook);
dispatch(updateUser({
addressBook: newAddressBook
}))
Expand Down
5 changes: 5 additions & 0 deletions src/containers/ConnectWallet/ConnectWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
KEPLR_LEDGER,
LOGIN_FAIL_TITLE
} from 'utils/constants'
import { authenticate } from 'utils/firebase'

const ConnectWallet = () => {

Expand All @@ -36,6 +37,10 @@ const ConnectWallet = () => {
setLoading(new Map(loading.set(ledgerType, true)))
const connectedUser = await connectUser(ledgerType)
dispatch(updateUser(connectedUser))

const firebaseToken = await authenticate(connectedUser.address!, ledgerType);
dispatch(updateUser({firebaseToken: firebaseToken}));

navigate('/welcome')

} catch (error) {
Expand Down
4 changes: 3 additions & 1 deletion src/store/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface userState {
chosenBalance?: Coin
connectedLedger?: string
newAddedAddress?: string
firebaseToken?: string
}

export const emptyWallet: Wallet = {
Expand Down Expand Up @@ -68,7 +69,8 @@ export const initialState: userState = {
addressBook: {},
chosenBalance: { denom: '', amount: '' },
connectedLedger: '',
newAddedAddress: ''
newAddedAddress: '',
firebaseToken: ''
}

export const userStateSlice = createSlice({
Expand Down
3 changes: 0 additions & 3 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { CHAIN_ID, COSMOSTATION_LEDGER, KEPLR_LEDGER, RPC_ADDRESS } from "./cons
import { userState } from "store/user";
import { connectKeplrLedger } from "ledgers/KeplrLedger";
import { connectCosmostationLedger } from "ledgers/CosmostationLedger";
import { Firebase } from "./firebase";
import { checkForAdminToken, getAccountBalances, getNativeBalance } from "./helpers";
import { isValidCudosAddress } from "./validation";

Expand Down Expand Up @@ -76,7 +75,6 @@ export const connectUser = async (ledgerType: string): Promise<userState> => {
const currentBalances = await getAccountBalances(address)
const admin = checkForAdminToken(currentBalances)
const userBalance = getNativeBalance(currentBalances)
const addressBook = await Firebase.getAddressBook(address)

const connectedUser: userState = {
accountName: accountName,
Expand All @@ -85,7 +83,6 @@ export const connectUser = async (ledgerType: string): Promise<userState> => {
balances: currentBalances,
nativeBalance: userBalance,
isAdmin: admin,
addressBook: addressBook,
connectedLedger: ledgerType,
}

Expand Down
10 changes: 5 additions & 5 deletions src/utils/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ export const CHAIN_ID = import.meta.env.VITE_APP_CHAIN_ID || process.env.VITE_AP
export const GAS_PRICE = import.meta.env.VITE_APP_GAS_PRICE || process.env.VITE_APP_GAS_PRICE || ""
export const GRAPHQL_URL = import.meta.env.VITE_APP_GRAPHQL_URL || process.env.VITE_APP_GRAPHQL_URL || ""
export const GRAPHQL_WS = import.meta.env.VITE_APP_GRAPHQL_WS || process.env.VITE_APP_GRAPHQL_WS || ""
export const FIREBASE_API_KEY = import.meta.env.VITE_APP_FIREBASE_API_KEY || process.env.VITE_APP_FIREBASE_API_KEY || ""
export const FIREBASE_AUTH_DOMAIN = import.meta.env.VITE_APP_FIREBASE_AUTH_DOMAIN || process.env.VITE_APP_FIREBASE_AUTH_DOMAIN || ""
export const FIREBASE_API_KEY = import.meta.env.VITE_APP_FIREBASE_API_KEY || process.env.VITE_APP_API_KEY || ""
export const FIREBASE_DOMAIN = import.meta.env.VITE_APP_FIREBASE_DOMAIN || process.env.VITE_APP_FIREBASE_DOMAIN || ""
export const FIREBASE_PROJECT_ID = import.meta.env.VITE_APP_FIREBASE_PROJECT_ID || process.env.VITE_APP_FIREBASE_PROJECT_ID || ""
export const FIREBASE_AUTH_EMAIL = import.meta.env.VITE_APP_FIREBASE_AUTH_EMAIL || process.env.VITE_APP_FIREBASE_AUTH_EMAIL || ""
export const FIREBASE_AUTH_PASSWORD = import.meta.env.VITE_APP_FIREBASE_AUTH_PASSWORD || process.env.VITE_APP_FIREBASE_AUTH_PASSWORD || ""
export const FIREBASE_COLLECTION_NAME = import.meta.env.VITE_APP_FIREBASE_COLLECTION_NAME || process.env.VITE_APP_FIREBASE_COLLECTION_NAME || ""
export const FIREBASE_AUTH_NONCE_URL = import.meta.env.VITE_APP_FIREBASE_AUTH_NONCE_URL || process.env.VITE_APP_FIREBASE_AUTH_NONCE_URL || ""
export const FIREBASE_AUTH_VERIFY_URL = import.meta.env.VITE_APP_FIREBASE_AUTH_VERIFY_URL || process.env.VITE_APP_FIREBASE_AUTH_VERIFY_URL || ""
export const FIREBASE_ADDRESS_BOOK_COLLECTION = import.meta.env.VITE_APP_FIREBASE_ADDRESS_BOOK_COLLECTION || process.env.VITE_APP_FIREBASE_ADDRESS_BOOK_COLLECTION || ""

// General config
export const ADMIN_TOKEN_DENOM = 'cudosAdmin'
Expand Down
72 changes: 39 additions & 33 deletions src/utils/firebase.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
import { FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN, FIREBASE_AUTH_EMAIL, FIREBASE_AUTH_PASSWORD, FIREBASE_COLLECTION_NAME, FIREBASE_PROJECT_ID } from "./constants";
import { FIREBASE_DOMAIN, FIREBASE_ADDRESS_BOOK_COLLECTION, FIREBASE_PROJECT_ID, FIREBASE_AUTH_NONCE_URL, FIREBASE_AUTH_VERIFY_URL, FIREBASE_API_KEY } from "./constants";
import { initializeApp } from 'firebase/app';
import { getAuth, signInWithEmailAndPassword } from 'firebase/auth';
import { getFirestore, Firestore, doc, getDoc, setDoc } from 'firebase/firestore/lite';
import { getAuth } from 'firebase/auth';
import { getFirestore, doc, getDoc, setDoc } from 'firebase/firestore/lite';
import { AddressBook } from "store/user";
import axios from "axios";
import { getSigningClient } from "./config";

export class Firebase {
static saveAddressBook = async (address: string, addressBook: AddressBook): Promise<void> => {
try {
const db = await useFirestore();
const addressBookDoc = doc(db, FIREBASE_COLLECTION_NAME, address);
return setDoc(addressBookDoc, { addressBook });
} catch {
throw new Error("Error while saving address book to Firebase")
}
};
const firebaseConfig = {
apiKey: FIREBASE_API_KEY,
authDomain: FIREBASE_DOMAIN,
projectId: FIREBASE_PROJECT_ID
};
const app = initializeApp(firebaseConfig);
const firestore = getFirestore(app);
export const auth = getAuth(app);

static getAddressBook = async (address: string): Promise<AddressBook> => {
try {
const db = await useFirestore();
const addressBookDoc = await getDoc(doc(db, FIREBASE_COLLECTION_NAME, address));
return addressBookDoc.data()?.addressBook ?? {};
} catch {
throw new Error("Error while getting address book from Firebase")
}
};
export const authenticate = async (address: string, connectedLedger: string) => {
try {
const nonceRes = await axios.post(FIREBASE_AUTH_NONCE_URL, { address });
const client = await getSigningClient(connectedLedger!);
const { signature, chainId, sequence, accountNumber } = await client.signNonceMsg(address!, nonceRes.data.nonce);
const verifyRes = await axios.post(FIREBASE_AUTH_VERIFY_URL, { address, signature, chainId, sequence, accountNumber });
return verifyRes.data.token;
} catch {
throw new Error("Error while getting address book from Firebase")
}
}

const useFirestore = async (): Promise<Firestore> => {
const firebaseConfig = {
apiKey: FIREBASE_API_KEY,
authDomain: FIREBASE_AUTH_DOMAIN,
projectId: FIREBASE_PROJECT_ID
};
export const getAddressBook = async (address): Promise<AddressBook> => {
try {
const addressBookDoc = await getDoc(doc(firestore, FIREBASE_ADDRESS_BOOK_COLLECTION, address));
return addressBookDoc.data()?.addressBook ?? {};
} catch {
throw new Error("Error while getting address book from Firebase")
}
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
await signInWithEmailAndPassword(auth, FIREBASE_AUTH_EMAIL, FIREBASE_AUTH_PASSWORD);
return getFirestore(app);
}
export const saveAddressBook = async (address: string, addressBook: AddressBook): Promise<void> => {
try {
const addressBookDoc = doc(firestore, FIREBASE_ADDRESS_BOOK_COLLECTION, address);
return setDoc(addressBookDoc, { addressBook });
} catch {
throw new Error("Error while saving address book to Firebase")
}
};
21 changes: 13 additions & 8 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2687,11 +2687,16 @@
prop-types "^15.8.1"
react-is "^18.2.0"

"@noble/hashes@^1", "@noble/hashes@^1.0.0":
"@noble/hashes@^1":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183"
integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==

"@noble/hashes@^1.0.0":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.3.tgz#360afc77610e0a61f3417e497dcf36862e4f8111"
integrity sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==

"@nodelib/[email protected]":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
Expand Down Expand Up @@ -4389,10 +4394,10 @@ csstype@^3.0.10, csstype@^3.0.2, csstype@^3.1.1:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9"
integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==

cudosjs@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cudosjs/-/cudosjs-1.1.0.tgz#5f127894b8aad518adc70983639fcc90a1f097f2"
integrity sha512-rMiIEMSPkUs7R1P5ytERODBw0kZBx0pzAeYFoUexaezD0GSNZppLJvUcFr5vVtZ5VA/5B1c9AXQCPX5DEWrcPw==
cudosjs@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/cudosjs/-/cudosjs-1.2.1.tgz#7ddde7c78981cc327a2695f834ba403bc3c350f7"
integrity sha512-WWakJxCtLV7EnyWAAC0+ICeLU+wIxqmCGeYLYee0qyXXjceyCa2AEYam6MoJOd1BRsQ+H+/yfWPor1lIAbdJ1A==
dependencies:
"@cosmjs/cosmwasm-stargate" "^0.28.4"
"@cosmjs/crypto" "^0.28.4"
Expand Down Expand Up @@ -6737,9 +6742,9 @@ [email protected], pako@~1.0.2:
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==

pako@^2.0.2:
version "2.0.4"
resolved "https://registry.yarnpkg.com/pako/-/pako-2.0.4.tgz#6cebc4bbb0b6c73b0d5b8d7e8476e2b2fbea576d"
integrity sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==
version "2.1.0"
resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==

param-case@^3.0.4:
version "3.0.4"
Expand Down

0 comments on commit 975f47b

Please sign in to comment.