@devtion/devcli 0.0.0-2319823 → 0.0.0-2cb7418

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -41,7 +41,7 @@ import {
41
41
  } from "../lib/utils.js"
42
42
  import { COMMAND_ERRORS, showError } from "../lib/errors.js"
43
43
  import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
44
- import { getAttestationLocalFilePath, localPaths } from "../lib/localConfigs.js"
44
+ import { getAttestationLocalFilePath, getLocalAuthMethod, localPaths } from "../lib/localConfigs.js"
45
45
  import theme from "../lib/theme.js"
46
46
  import { checkAndMakeNewDirectoryIfNonexistent, writeFile } from "../lib/files.js"
47
47
 
@@ -281,12 +281,12 @@ export const handleDiskSpaceRequirementForNextContribution = async (
281
281
  )} since is based on the aggregate free memory on your disks but some may not be detected!\n`
282
282
  )
283
283
 
284
- const { confirmation } = await askForConfirmation(
284
+ const { confirmationEnoughMemory } = await askForConfirmation(
285
285
  `Please, we kindly ask you to continue with the contribution if you have noticed the estimate is wrong and you have enough memory in your machine`,
286
286
  "Continue",
287
287
  "Exit"
288
288
  )
289
- wannaContributeOrHaveEnoughMemory = !!confirmation
289
+ wannaContributeOrHaveEnoughMemory = !!confirmationEnoughMemory
290
290
 
291
291
  if (circuitSequencePosition > 1) {
292
292
  console.log(
@@ -419,14 +419,19 @@ export const handlePublicAttestation = async (
419
419
 
420
420
  await sleep(1000) // workaround for file descriptor unexpected close.
421
421
 
422
- const gistUrl = await publishGist(participantAccessToken, publicAttestation, ceremonyName, ceremonyPrefix)
423
-
424
- console.log(
425
- `\n${theme.symbols.info} Your public attestation has been successfully posted as Github Gist (${theme.text.bold(
426
- theme.text.underlined(gistUrl)
427
- )})`
428
- )
422
+ let gistUrl = ""
423
+ const isGithub = getLocalAuthMethod() === "github"
424
+ if (isGithub) {
425
+ gistUrl = await publishGist(participantAccessToken, publicAttestation, ceremonyName, ceremonyPrefix)
429
426
 
427
+ console.log(
428
+ `\n${
429
+ theme.symbols.info
430
+ } Your public attestation has been successfully posted as Github Gist (${theme.text.bold(
431
+ theme.text.underlined(gistUrl)
432
+ )})`
433
+ )
434
+ }
430
435
  // Prepare a ready-to-share tweet.
431
436
  await handleTweetGeneration(ceremonyName, gistUrl)
432
437
  }
@@ -514,6 +519,8 @@ export const listenToCeremonyCircuitDocumentChanges = (
514
519
  })
515
520
  }
516
521
 
522
+ let contributionInProgress = false
523
+
517
524
  /**
518
525
  * Listen to current authenticated participant document changes.
519
526
  * @dev this is the core business logic related to the execution of the contribute command.
@@ -706,6 +713,12 @@ export const listenToParticipantDocumentChanges = async (
706
713
 
707
714
  // Scenario (3.B).
708
715
  if (isCurrentContributor && hasResumableStep && startingOrResumingContribution) {
716
+ if (contributionInProgress) {
717
+ console.warn(
718
+ `\n${theme.symbols.warning} Received instruction to start/resume contribution but contribution is already in progress...[skipping]`
719
+ )
720
+ return
721
+ }
709
722
  // Communicate resume / start of the contribution to participant.
710
723
  await simpleLoader(
711
724
  `${
@@ -715,18 +728,24 @@ export const listenToParticipantDocumentChanges = async (
715
728
  3000
716
729
  )
717
730
 
718
- // Start / Resume the contribution for the participant.
719
- await handleStartOrResumeContribution(
720
- cloudFunctions,
721
- firestoreDatabase,
722
- ceremony,
723
- circuit,
724
- participant,
725
- entropy,
726
- providerUserId,
727
- false, // not finalizing.
728
- circuits.length
729
- )
731
+ try {
732
+ contributionInProgress = true
733
+
734
+ // Start / Resume the contribution for the participant.
735
+ await handleStartOrResumeContribution(
736
+ cloudFunctions,
737
+ firestoreDatabase,
738
+ ceremony,
739
+ circuit,
740
+ participant,
741
+ entropy,
742
+ providerUserId,
743
+ false, // not finalizing.
744
+ circuits.length
745
+ )
746
+ } finally {
747
+ contributionInProgress = false
748
+ }
730
749
  }
731
750
  // Scenario (3.A).
732
751
  else if (isWaitingForContribution)
@@ -938,7 +957,11 @@ const contribute = async (opt: any) => {
938
957
  } else selectedCeremony = selectedCeremonyDocument.at(0)
939
958
  } else {
940
959
  // Prompt the user to select a ceremony from the opened ones.
941
- selectedCeremony = await promptForCeremonySelection(ceremoniesOpenedForContributions, false)
960
+ selectedCeremony = await promptForCeremonySelection(
961
+ ceremoniesOpenedForContributions,
962
+ false,
963
+ "Which ceremony would you like to contribute to?"
964
+ )
942
965
  }
943
966
 
944
967
  // Get selected ceremony circuit(s) documents.
@@ -952,7 +975,7 @@ const contribute = async (opt: any) => {
952
975
  const userData = userDoc.data()
953
976
  if (!userData) {
954
977
  spinner.fail(
955
- `Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`
978
+ `Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not eligible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`
956
979
  )
957
980
  process.exit(0)
958
981
  }
@@ -74,7 +74,7 @@ export const handleVerificationKey = async (
74
74
  // Write the verification key locally.
75
75
  writeLocalJsonFile(verificationKeyLocalFilePath, vKey)
76
76
 
77
- await sleep(3000) // workaound for file descriptor.
77
+ await sleep(3000) // workaround for file descriptor.
78
78
 
79
79
  // Upload verification key to storage.
80
80
  await multiPartUpload(
@@ -122,7 +122,7 @@ export const handleVerifierSmartContract = async (
122
122
  // Write the verification key locally.
123
123
  writeFile(verifierContractLocalFilePath, verifierCode)
124
124
 
125
- await sleep(3000) // workaound for file descriptor.
125
+ await sleep(3000) // workaround for file descriptor.
126
126
 
127
127
  // Upload verifier smart contract to storage.
128
128
  await multiPartUpload(
@@ -177,7 +177,7 @@ export const handleCircuitFinalization = async (
177
177
  circuitsLength
178
178
  )
179
179
 
180
- await sleep(2000) // workaound for descriptors.
180
+ await sleep(2000) // workaround for descriptors.
181
181
 
182
182
  // Extract data.
183
183
  const { prefix: circuitPrefix } = circuit.data
@@ -269,7 +269,11 @@ const finalize = async (opt: any) => {
269
269
  )
270
270
 
271
271
  // Prompt for ceremony selection.
272
- const selectedCeremony = await promptForCeremonySelection(ceremoniesClosedForFinalization, true)
272
+ const selectedCeremony = await promptForCeremonySelection(
273
+ ceremoniesClosedForFinalization,
274
+ true,
275
+ "Which ceremony would you like to finalize?"
276
+ )
273
277
 
274
278
  // Get coordinator participant document.
275
279
  let participant = await getDocumentById(
@@ -1,5 +1,7 @@
1
1
  export { default as setup } from "./setup.js"
2
2
  export { default as auth } from "./auth.js"
3
+ export { default as authBandada } from "./authBandada.js"
4
+ export { default as authSIWE } from "./authSIWE.js"
3
5
  export { default as contribute } from "./contribute.js"
4
6
  export { default as observe } from "./observe.js"
5
7
  export { default as finalize } from "./finalize.js"
@@ -6,7 +6,7 @@ import { showError } from "../lib/errors.js"
6
6
  import { askForConfirmation } from "../lib/prompts.js"
7
7
  import { customSpinner, sleep, terminate } from "../lib/utils.js"
8
8
  import theme from "../lib/theme.js"
9
- import { deleteLocalAccessToken } from "../lib/localConfigs.js"
9
+ import { deleteLocalAccessToken, deleteLocalAuthMethod, deleteLocalBandadaIdentity } from "../lib/localConfigs.js"
10
10
 
11
11
  /**
12
12
  * Logout command.
@@ -52,7 +52,9 @@ const logout = async () => {
52
52
  await signOut(auth)
53
53
 
54
54
  // Delete local token.
55
+ deleteLocalAuthMethod()
55
56
  deleteLocalAccessToken()
57
+ deleteLocalBandadaIdentity()
56
58
 
57
59
  await sleep(3000) // ~3s.
58
60
 
@@ -147,7 +147,11 @@ const observe = async () => {
147
147
  const runningCeremoniesDocs = await getOpenedCeremonies(firestoreDatabase)
148
148
 
149
149
  // Ask to select a ceremony.
150
- const ceremony = await promptForCeremonySelection(runningCeremoniesDocs, false)
150
+ const ceremony = await promptForCeremonySelection(
151
+ runningCeremoniesDocs,
152
+ false,
153
+ "Which ceremony would you like to observe?"
154
+ )
151
155
 
152
156
  console.log(`${logSymbols.info} Refresh rate set to ~3 seconds for waiting queue updates\n`)
153
157
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { zKey } from "snarkjs"
4
4
  import boxen from "boxen"
5
- import { createWriteStream, Dirent, renameSync } from "fs"
5
+ import { createWriteStream, Dirent, renameSync, existsSync } from "fs"
6
6
  import { pipeline } from "node:stream"
7
7
  import { promisify } from "node:util"
8
8
  import fetch from "node-fetch"
@@ -537,20 +537,33 @@ const setup = async (cmd: { template?: string; auth?: string }) => {
537
537
  `clock`
538
538
  )
539
539
  spinner.start()
540
- await zKey.newZKey(
541
- r1csLocalPathAndFileName,
542
- getPotLocalFilePath(circuit.files.potFilename),
543
- zkeyLocalPathAndFileName,
544
- undefined
545
- )
546
- spinner.succeed(
547
- `Generation of the genesis zKey for citcui ${theme.text.bold(circuit.name)} completed successfully`
548
- )
549
540
 
541
+ if (existsSync(zkeyLocalPathAndFileName)) {
542
+ spinner.succeed(
543
+ `The genesis zKey for circuit ${theme.text.bold(circuit.name)} is already present on disk`
544
+ )
545
+ } else {
546
+ await zKey.newZKey(
547
+ r1csLocalPathAndFileName,
548
+ getPotLocalFilePath(circuit.files.potFilename),
549
+ zkeyLocalPathAndFileName,
550
+ undefined
551
+ )
552
+ spinner.succeed(
553
+ `Generation of the genesis zKey for circuit ${theme.text.bold(circuit.name)} completed successfully`
554
+ )
555
+ }
556
+
557
+ const hashSpinner = customSpinner(
558
+ `Calculating hashes for circuit ${theme.text.bold(circuit.name)}...`,
559
+ `clock`
560
+ )
561
+ hashSpinner.start()
550
562
  // 4. calculate the hashes
551
563
  const wasmBlake2bHash = await blake512FromPath(wasmLocalPathAndFileName)
552
564
  const potBlake2bHash = await blake512FromPath(getPotLocalFilePath(circuit.files.potFilename))
553
565
  const initialZkeyBlake2bHash = await blake512FromPath(zkeyLocalPathAndFileName)
566
+ hashSpinner.succeed(`Hashes for circuit ${theme.text.bold(circuit.name)} calculated successfully`)
554
567
 
555
568
  // 5. upload the artifacts
556
569
 
package/src/index.ts CHANGED
@@ -7,6 +7,8 @@ import { fileURLToPath } from "url"
7
7
  import {
8
8
  setup,
9
9
  auth,
10
+ authSIWE,
11
+ authBandada,
10
12
  contribute,
11
13
  observe,
12
14
  finalize,
@@ -15,6 +17,7 @@ import {
15
17
  validate,
16
18
  listCeremonies
17
19
  } from "./commands/index.js"
20
+ import setCeremonyCommands from "./commands/ceremony/index.js"
18
21
 
19
22
  // Get pkg info (e.g., name, version).
20
23
  const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
@@ -26,6 +29,14 @@ program.name(name).description(description).version(version)
26
29
 
27
30
  // User commands.
28
31
  program.command("auth").description("authenticate yourself using your Github account (OAuth 2.0)").action(auth)
32
+ program
33
+ .command("auth-bandada")
34
+ .description("authenticate yourself in a privacy-perserving manner using Bandada")
35
+ .action(authBandada)
36
+ program
37
+ .command("auth-siwe")
38
+ .description("authenticate yourself using your Ethereum account (Sign In With Ethereum - SIWE)")
39
+ .action(authSIWE)
29
40
  program
30
41
  .command("contribute")
31
42
  .description("compute contributions for a Phase2 Trusted Setup ceremony circuits")
@@ -44,27 +55,27 @@ program
44
55
  .action(logout)
45
56
  program
46
57
  .command("validate")
47
- .description("Validate that a Ceremony Setup file is correct")
58
+ .description("validate that a Ceremony Setup file is correct")
48
59
  .requiredOption("-t, --template <path>", "The path to the ceremony setup template", "")
49
60
  .option("-c, --constraints <number>", "The number of constraints to check against")
50
61
  .action(validate)
51
62
 
52
63
  // Only coordinator commands.
53
- const ceremony = program.command("coordinate").description("commands for coordinating a ceremony")
64
+ const coordinate = program.command("coordinate").description("commands for coordinating a ceremony")
54
65
 
55
- ceremony
66
+ coordinate
56
67
  .command("setup")
57
68
  .description("setup a Groth16 Phase 2 Trusted Setup ceremony for zk-SNARK circuits")
58
69
  .option("-t, --template <path>", "The path to the ceremony setup template", "")
59
70
  .option("-a, --auth <string>", "The Github OAuth 2.0 token", "")
60
71
  .action(setup)
61
72
 
62
- ceremony
73
+ coordinate
63
74
  .command("observe")
64
75
  .description("observe in real-time the waiting queue of each ceremony circuit")
65
76
  .action(observe)
66
77
 
67
- ceremony
78
+ coordinate
68
79
  .command("finalize")
69
80
  .description(
70
81
  "finalize a Phase2 Trusted Setup ceremony by applying a beacon, exporting verification key and verifier contract"
@@ -72,4 +83,6 @@ ceremony
72
83
  .option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
73
84
  .action(finalize)
74
85
 
86
+ setCeremonyCommands(program)
87
+
75
88
  program.parseAsync(process.argv)
@@ -0,0 +1,51 @@
1
+ import { ApiSdk, GroupResponse } from "@bandada/api-sdk"
2
+ import { Identity } from "@semaphore-protocol/identity"
3
+ import open from "open"
4
+
5
+ import { askForConfirmation } from "../lib/prompts.js"
6
+ import { showError } from "./errors.js"
7
+ import theme from "../lib/theme.js"
8
+
9
+ const { BANDADA_API_URL } = process.env
10
+
11
+ const bandadaApi = new ApiSdk(BANDADA_API_URL)
12
+
13
+ export const getGroup = async (groupId: string): Promise<GroupResponse | null> => {
14
+ try {
15
+ const group = await bandadaApi.getGroup(groupId)
16
+ return group
17
+ } catch (error: any) {
18
+ showError(`Bandada getGroup error: ${error}`, true)
19
+ return null
20
+ }
21
+ }
22
+
23
+ export const getMembersOfGroup = async (groupId: string): Promise<string[] | null> => {
24
+ try {
25
+ const group = await bandadaApi.getGroup(groupId)
26
+ return group.members
27
+ } catch (error: any) {
28
+ showError(`Bandada getMembersOfGroup error: ${error}`, true)
29
+ return null
30
+ }
31
+ }
32
+
33
+ export const addMemberToGroup = async (groupId: string, dashboardUrl: string, identity: Identity) => {
34
+ const commitment = identity.commitment.toString()
35
+ const group = await bandadaApi.getGroup(groupId)
36
+ const providerName = group.credentials.id.split("_")[0].toLowerCase()
37
+
38
+ // 6. open a new window with the url:
39
+ const url = `${dashboardUrl}credentials?group=${groupId}&member=${commitment}&provider=${providerName}`
40
+ console.log(`${theme.text.bold(`Verification URL:`)} ${theme.text.underlined(url)}`)
41
+ open(url)
42
+
43
+ const { confirmation } = await askForConfirmation("Did you join the Bandada group in the browser?")
44
+ if (!confirmation) showError("You must join the Bandada group to continue the login process", true)
45
+ }
46
+
47
+ export const isGroupMember = async (groupId: string, identity: Identity): Promise<boolean> => {
48
+ const commitment = identity.commitment.toString()
49
+ const isMember: boolean = await bandadaApi.isGroupMember(groupId, commitment)
50
+ return isMember
51
+ }
package/src/lib/errors.ts CHANGED
@@ -6,7 +6,7 @@ export const CORE_SERVICES_ERRORS = {
6
6
  FIREBASE_TOKEN_EXPIRED_REMOVED_PERMISSIONS: `The Github authorization has failed due to lack of association between your account and the CLI`,
7
7
  FIREBASE_USER_DISABLED: `The Github account has been suspended by the ceremony coordinator(s), blocking the possibility of contribution. Please, contact them to understand the motivation behind it.`,
8
8
  FIREBASE_FAILED_CREDENTIALS_VERIFICATION: `Firebase cannot verify your Github credentials due to network errors. Please, try once again later.`,
9
- FIREBASE_NETWORK_ERROR: `Unable to reach Firebase due to network erros. Please, try once again later and make sure your Internet connection is stable.`,
9
+ FIREBASE_NETWORK_ERROR: `Unable to reach Firebase due to network errors. Please, try once again later and make sure your Internet connection is stable.`,
10
10
  FIREBASE_CEREMONY_NOT_OPENED: `There are no ceremonies opened to contributions`,
11
11
  FIREBASE_CEREMONY_NOT_CLOSED: `There are no ceremonies ready to finalization`,
12
12
  AWS_CEREMONY_BUCKET_CREATION: `Unable to create a new bucket for the ceremony. Something went wrong during the creation. Please, repeat the process by providing a new ceremony name of the ceremony.`,
@@ -24,6 +24,14 @@ const config = new Conf({
24
24
  accessToken: {
25
25
  type: "string",
26
26
  default: ""
27
+ },
28
+ bandadaIdentity: {
29
+ type: "string",
30
+ default: ""
31
+ },
32
+ authMethod: {
33
+ type: "string",
34
+ default: ""
27
35
  }
28
36
  }
29
37
  })
@@ -91,6 +99,52 @@ export const setLocalAccessToken = (token: string) => config.set("accessToken",
91
99
  */
92
100
  export const deleteLocalAccessToken = () => config.delete("accessToken")
93
101
 
102
+ /**
103
+ * Return the Bandada identity, if present.
104
+ * @returns <string | undefined> - the Bandada identity if present, otherwise undefined.
105
+ */
106
+ export const getLocalBandadaIdentity = (): string | unknown => config.get("bandadaIdentity")
107
+
108
+ /**
109
+ * Check if the Bandada identity exists in the local storage.
110
+ * @returns <boolean>
111
+ */
112
+ export const checkLocalBandadaIdentity = (): boolean => config.has("bandadaIdentity") && !!config.get("bandadaIdentity")
113
+
114
+ /**
115
+ * Set the Bandada identity.
116
+ * @param identity <string> - the Bandada identity to be stored.
117
+ */
118
+ export const setLocalBandadaIdentity = (identity: string) => config.set("bandadaIdentity", identity)
119
+
120
+ /**
121
+ * Delete the stored Bandada identity.
122
+ */
123
+ export const deleteLocalBandadaIdentity = () => config.delete("bandadaIdentity")
124
+
125
+ /**
126
+ * Return the authentication method, if present.
127
+ * @returns <string | undefined> - the authentication method if present, otherwise undefined.
128
+ */
129
+ export const getLocalAuthMethod = (): string | unknown => config.get("authMethod")
130
+
131
+ /**
132
+ * Check if the authentication method exists in the local storage.
133
+ * @returns <boolean>
134
+ */
135
+ export const checkLocalAuthMethod = (): boolean => config.has("authMethod") && !!config.get("authMethod")
136
+
137
+ /**
138
+ * Set the authentication method.
139
+ * @param method <string> - the authentication method to be stored.
140
+ */
141
+ export const setLocalAuthMethod = (method: string) => config.set("authMethod", method)
142
+
143
+ /**
144
+ * Delete the stored authentication method.
145
+ */
146
+ export const deleteLocalAuthMethod = () => config.delete("authMethod")
147
+
94
148
  /**
95
149
  * Get the complete local file path.
96
150
  * @param cwd <string> - the current working directory path.
@@ -661,7 +661,8 @@ export const promptPotSelector = async (options: Array<string>): Promise<string>
661
661
  */
662
662
  export const promptForCeremonySelection = async (
663
663
  ceremoniesDocuments: Array<FirebaseDocumentInfo>,
664
- isFinalizing: boolean
664
+ isFinalizing: boolean,
665
+ messageToDisplay?: string
665
666
  ): Promise<FirebaseDocumentInfo> => {
666
667
  // Prepare state.
667
668
  const choices: Array<Choice> = []
@@ -686,11 +687,7 @@ export const promptForCeremonySelection = async (
686
687
  const { ceremony } = await prompts({
687
688
  type: "select",
688
689
  name: "ceremony",
689
- message: theme.text.bold(
690
- !isFinalizing
691
- ? "Which ceremony would you like to contribute to?"
692
- : "Which ceremony would you like to finalize?"
693
- ),
690
+ message: theme.text.bold(messageToDisplay),
694
691
  choices,
695
692
  initial: 0
696
693
  })
@@ -6,13 +6,18 @@ import {
6
6
  import clear from "clear"
7
7
  import figlet from "figlet"
8
8
  import { FirebaseApp } from "firebase/app"
9
- import { OAuthCredential } from "firebase/auth"
9
+ import { OAuthCredential, getAuth, signInWithCustomToken } from "firebase/auth"
10
10
  import dotenv from "dotenv"
11
11
  import { fileURLToPath } from "url"
12
12
  import { dirname } from "path"
13
13
  import { AuthUser } from "../types/index.js"
14
14
  import { CONFIG_ERRORS, CORE_SERVICES_ERRORS, showError, THIRD_PARTY_SERVICES_ERRORS } from "./errors.js"
15
- import { checkLocalAccessToken, deleteLocalAccessToken, getLocalAccessToken } from "./localConfigs.js"
15
+ import {
16
+ checkLocalAccessToken,
17
+ deleteLocalAccessToken,
18
+ getLocalAccessToken,
19
+ getLocalAuthMethod
20
+ } from "./localConfigs.js"
16
21
  import theme from "./theme.js"
17
22
  import { exchangeGithubTokenForCredentials, getGithubProviderUserId, getUserHandleFromProviderUserId } from "./utils.js"
18
23
 
@@ -164,22 +169,42 @@ export const checkAuth = async (firebaseApp: FirebaseApp): Promise<AuthUser> =>
164
169
  // Retrieve local access token.
165
170
  const token = String(getLocalAccessToken())
166
171
 
167
- // Get credentials.
168
- const credentials = exchangeGithubTokenForCredentials(token)
169
-
170
- // Sign in to Firebase using credentials.
171
- await signInToFirebase(firebaseApp, credentials)
172
+ let providerUserId: string
173
+ let username: string
174
+ const authMethod = getLocalAuthMethod()
175
+ switch (authMethod) {
176
+ case "github": {
177
+ // Get credentials.
178
+ const credentials = exchangeGithubTokenForCredentials(token)
179
+ // Sign in to Firebase using credentials.
180
+ await signInToFirebase(firebaseApp, credentials)
181
+ // Get Github unique identifier (handle-id).
182
+ providerUserId = await getGithubProviderUserId(String(token))
183
+ username = getUserHandleFromProviderUserId(providerUserId)
184
+ break
185
+ }
186
+ case "bandada": {
187
+ const userCredentials = await signInWithCustomToken(getAuth(), token)
188
+ providerUserId = userCredentials.user.uid
189
+ username = providerUserId
190
+ break
191
+ }
192
+ case "siwe": {
193
+ const userCredentials = await signInWithCustomToken(getAuth(), token)
194
+ providerUserId = userCredentials.user.uid
195
+ username = providerUserId
196
+ break
197
+ }
198
+ default: {
199
+ break
200
+ }
201
+ }
172
202
 
173
203
  // Get current authenticated user.
174
204
  const user = getCurrentFirebaseAuthUser(firebaseApp)
175
205
 
176
- // Get Github unique identifier (handle-id).
177
- const providerUserId = await getGithubProviderUserId(String(token))
178
-
179
206
  // Greet the user.
180
- console.log(
181
- `Greetings, @${theme.text.bold(getUserHandleFromProviderUserId(providerUserId))} ${theme.emojis.wave}\n`
182
- )
207
+ console.log(`Greetings, @${theme.text.bold(username)} ${theme.emojis.wave}\n`)
183
208
 
184
209
  return {
185
210
  user,
package/src/lib/utils.ts CHANGED
@@ -155,7 +155,9 @@ export const getPublicAttestationGist = async (
155
155
  * @returns <string> - the third-party provider handle of the user.
156
156
  */
157
157
  export const getUserHandleFromProviderUserId = (providerUserId: string): string => {
158
- if (providerUserId.indexOf("-") === -1) showError(THIRD_PARTY_SERVICES_ERRORS.GITHUB_GET_GITHUB_ACCOUNT_INFO, true)
158
+ if (providerUserId.indexOf("-") === -1) {
159
+ return providerUserId
160
+ }
159
161
 
160
162
  return providerUserId.split("-")[0]
161
163
  }
@@ -68,3 +68,78 @@ export type GithubGistFile = {
68
68
  raw_url: string
69
69
  size: number
70
70
  }
71
+
72
+ /**
73
+ * Define the return object of the function that verifies the Bandada membership and proof.
74
+ * @typedef {Object} VerifiedBandadaResponse
75
+ * @property {boolean} valid - true if the proof is valid and the user is a member of the group; otherwise false.
76
+ * @property {string} message - a message describing the result of the verification.
77
+ * @property {string} token - the custom access token.
78
+ */
79
+ export type VerifiedBandadaResponse = {
80
+ valid: boolean
81
+ message: string
82
+ token: string
83
+ }
84
+
85
+ /**
86
+ * Define the return object of the device code uri request.
87
+ * @typedef {Object} OAuthDeviceCodeResponse
88
+ * @property {string} device_code - the device code.
89
+ * @property {string} user_code - the user code.
90
+ * @property {string} verification_uri - the verification uri.
91
+ * @property {number} expires_in - the expiration time in seconds.
92
+ * @property {number} interval - the interval time in seconds.
93
+ * @property {string} verification_uri_complete - the complete verification uri.
94
+ * @property {string} error - in case there was an error, show the code
95
+ * @property {string} error_description - error details.
96
+ * @property {string} error_uri - error uri.
97
+ */
98
+ export type OAuthDeviceCodeResponse = {
99
+ device_code: string
100
+ user_code: string
101
+ verification_uri: string
102
+ expires_in: number
103
+ interval: number
104
+ verification_uri_complete: string
105
+ // error response should contain
106
+ error?: string
107
+ error_description?: string
108
+ error_uri?: string
109
+ }
110
+
111
+ /**
112
+ * Define the return object of the polling endpoint
113
+ * @typedef {Object} OAuthTokenResponse
114
+ * @property {string} access_token - the resulting device flow token
115
+ * @property {string} token_type - token type
116
+ * @property {number} expires_in - when does the token expires
117
+ * @property {string} scope - the scope requested by the initial device flow endpoint
118
+ * @property {string} refresh_token - refresh token
119
+ * @property {string} id_token - id token
120
+ * @property {string} error - in case there was an error, show the code
121
+ * @property {string} error_description - error details
122
+ */
123
+ export type OAuthTokenResponse = {
124
+ access_token: string
125
+ token_type: string
126
+ expires_in: number
127
+ scope: string
128
+ refresh_token: string
129
+ id_token: string
130
+ // error response should contain
131
+ error?: string
132
+ error_description?: string
133
+ }
134
+
135
+ /**
136
+ * @typedef {Object} CheckNonceOfSIWEAddressResponse
137
+ * @property {boolean} valid - if the checking was valid or not
138
+ * @property {string} message - more information about the validity
139
+ * @property {string} token - token to sign into Firebase
140
+ */
141
+ export type CheckNonceOfSIWEAddressResponse = {
142
+ valid: boolean
143
+ message: string
144
+ token: string
145
+ }