@chainwayxyz/phase2cli
Version:
All-in-one interactive command-line for interfacing with zkSNARK Phase 2 Trusted Setup ceremonies
121 lines (110 loc) • 4.86 kB
text/typescript
import { Identity } from "@semaphore-protocol/identity"
import { commonTerms } from "@p0tion/actions"
import { httpsCallable } from "firebase/functions"
import { groth16 } from "snarkjs"
import { getAuth, signInWithCustomToken } from "firebase/auth"
import prompts from "prompts"
import { getLocalDirname } from "../lib/files.js"
import theme from "../lib/theme.js"
import { customSpinner } from "../lib/utils.js"
import { VerifiedBandadaResponse } from "../types/index.js"
import { showError } from "../lib/errors.js"
import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
import { addMemberToGroup, isGroupMember } from "../lib/bandada.js"
import {
checkLocalBandadaIdentity,
deleteLocalAccessToken,
deleteLocalAuthMethod,
deleteLocalBandadaIdentity,
getLocalBandadaIdentity,
setLocalAccessToken,
setLocalAuthMethod,
setLocalBandadaIdentity
} from "../lib/localConfigs.js"
const { BANDADA_DASHBOARD_URL, BANDADA_GROUP_ID } = process.env
const authBandada = async () => {
try {
const { firebaseFunctions } = await bootstrapCommandExecutionAndServices()
const spinner = customSpinner(`Checking identity string for Semaphore...`, `clock`)
spinner.start()
// 1. check if _identity string exists in local storage
let identityString: string | unknown
const isIdentityStringStored = checkLocalBandadaIdentity()
if (isIdentityStringStored) {
identityString = getLocalBandadaIdentity()
spinner.succeed(`Identity seed found\n`)
} else {
spinner.warn(`Identity seed not found\n`)
// 2. generate a random _identity string and save it in local storage
const { seed } = await prompts({
type: "text",
name: "seed",
message: theme.text.bold(`Enter a secret string to use as your identity seed in Semaphore:`),
initial: false
})
identityString = seed as string
setLocalBandadaIdentity(identityString as string)
}
// 3. create a semaphore identity with _identity string as a seed
const identity = new Identity(identityString as string)
// 4. check if the user is a member of the group
console.log(`Checking Bandada membership...`)
const isMember = await isGroupMember(BANDADA_GROUP_ID, identity)
if (!isMember) {
await addMemberToGroup(BANDADA_GROUP_ID, BANDADA_DASHBOARD_URL, identity)
}
// 5. generate a proof that the user owns the commitment.
spinner.text = `Generating proof of identity...`
spinner.start()
// publicSignals = [hash(externalNullifier, identityNullifier), commitment]
const initDirectoryName = getLocalDirname()
const directoryName = initDirectoryName.includes("/src") ? "." : initDirectoryName
const { proof, publicSignals } = await groth16.fullProve(
{
identityTrapdoor: identity.trapdoor,
identityNullifier: identity.nullifier,
externalNullifier: BANDADA_GROUP_ID
},
`${directoryName}/public/mini-semaphore.wasm`,
`${directoryName}/public/mini-semaphore.zkey`
)
spinner.succeed(`Proof generated.\n`)
spinner.text = `Sending proof to verification...`
spinner.start()
// 6. send proof to a cloud function that verifies it and checks membership
const cf = httpsCallable(firebaseFunctions, commonTerms.cloudFunctionsNames.bandadaValidateProof)
const result = await cf({
proof,
publicSignals
})
const { valid, token, message } = result.data as VerifiedBandadaResponse
if (!valid) {
showError(message, true)
deleteLocalAuthMethod()
deleteLocalAccessToken()
deleteLocalBandadaIdentity()
}
spinner.succeed(`Proof verified.\n`)
spinner.text = `Authenticating...`
spinner.start()
// 7. Auth to p0tion firebase
const credentials = await signInWithCustomToken(getAuth(), token)
setLocalAuthMethod("bandada")
setLocalAccessToken(token)
spinner.succeed(`Authenticated as ${theme.text.bold(credentials.user.uid)}.`)
console.log(
`\n${theme.symbols.warning} You can always log out by running the ${theme.text.bold(
`phase2cli logout`
)} command`
)
} catch (error) {
// Delete local token.
console.log("An error crashed the process. Deleting local token and identity.")
console.error(error)
deleteLocalAuthMethod()
deleteLocalAccessToken()
deleteLocalBandadaIdentity()
}
process.exit(0)
}
export default authBandada