@devtion/actions 0.0.0-270e9e0 → 0.0.0-56491a8

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.
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @module @p0tion/actions
3
- * @version 1.0.4
2
+ * @module @devtion/actions
3
+ * @version 1.0.6
4
4
  * @file A set of actions and helpers for CLI commands
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
@@ -17,7 +17,7 @@ import crypto from 'crypto';
17
17
  import blake from 'blakejs';
18
18
  import { utils } from 'ffjavascript';
19
19
  import winston from 'winston';
20
- import { S3Client, HeadObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
20
+ import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
21
21
  import { pipeline, Readable } from 'stream';
22
22
  import { promisify } from 'util';
23
23
  import { initializeApp } from 'firebase/app';
@@ -244,6 +244,12 @@ const commonTerms = {
244
244
  verificationStartedAt: "verificationStartedAt"
245
245
  }
246
246
  },
247
+ avatars: {
248
+ name: "avatars",
249
+ fields: {
250
+ avatarUrl: "avatarUrl"
251
+ }
252
+ },
247
253
  ceremonies: {
248
254
  name: "ceremonies",
249
255
  fields: {
@@ -1085,42 +1091,34 @@ const parseCeremonyFile = async (path, cleanup = false) => {
1085
1091
  circuitArtifacts.push({
1086
1092
  artifacts: artifacts
1087
1093
  });
1088
- const r1csPath = artifacts.r1csStoragePath;
1089
- const wasmPath = artifacts.wasmStoragePath;
1090
1094
  // where we storing the r1cs downloaded
1091
1095
  const localR1csPath = `./${circuitData.name}.r1cs`;
1096
+ // where we storing the wasm downloaded
1097
+ const localWasmPath = `./${circuitData.name}.wasm`;
1092
1098
  // check that the artifacts exist in S3
1093
1099
  // we don't need any privileges to download this
1094
1100
  // just the correct region
1095
- const s3 = new S3Client({ region: artifacts.region });
1096
- try {
1097
- await s3.send(new HeadObjectCommand({
1098
- Bucket: artifacts.bucket,
1099
- Key: r1csPath
1100
- }));
1101
- }
1102
- catch (error) {
1103
- throw new Error(`The r1cs file (${r1csPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`);
1104
- }
1105
- try {
1106
- await s3.send(new HeadObjectCommand({
1107
- Bucket: artifacts.bucket,
1108
- Key: wasmPath
1109
- }));
1110
- }
1111
- catch (error) {
1112
- throw new Error(`The wasm file (${wasmPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`);
1113
- }
1101
+ const s3 = new S3Client({
1102
+ region: artifacts.region,
1103
+ credentials: undefined
1104
+ });
1114
1105
  // download the r1cs to extract the metadata
1115
1106
  const command = new GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.r1csStoragePath });
1116
1107
  const response = await s3.send(command);
1117
1108
  const streamPipeline = promisify(pipeline);
1118
1109
  if (response.$metadata.httpStatusCode !== 200)
1119
- throw new Error("There was an error while trying to download the r1cs file. Please check that the file has the correct permissions (public) set.");
1110
+ throw new Error(`There was an error while trying to download the r1cs file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`);
1120
1111
  if (response.Body instanceof Readable)
1121
1112
  await streamPipeline(response.Body, fs.createWriteStream(localR1csPath));
1122
1113
  // extract the metadata from the r1cs
1123
1114
  const metadata = getR1CSInfo(localR1csPath);
1115
+ // download wasm too to ensure it's available
1116
+ const wasmCommand = new GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.wasmStoragePath });
1117
+ const wasmResponse = await s3.send(wasmCommand);
1118
+ if (wasmResponse.$metadata.httpStatusCode !== 200)
1119
+ throw new Error(`There was an error while trying to download the wasm file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`);
1120
+ if (wasmResponse.Body instanceof Readable)
1121
+ await streamPipeline(wasmResponse.Body, fs.createWriteStream(localWasmPath));
1124
1122
  // validate that the circuit hash and template links are valid
1125
1123
  const template = circuitData.template;
1126
1124
  const URLMatch = template.source.match(urlPattern);
@@ -1168,35 +1166,53 @@ const parseCeremonyFile = async (path, cleanup = false) => {
1168
1166
  // check that the timeout is provided for the correct configuration
1169
1167
  let dynamicThreshold;
1170
1168
  let fixedTimeWindow;
1169
+ let circuit = {};
1171
1170
  if (data.timeoutMechanismType === "DYNAMIC" /* CeremonyTimeoutType.DYNAMIC */) {
1172
1171
  if (circuitData.dynamicThreshold <= 0)
1173
1172
  throw new Error("The dynamic threshold should be > 0.");
1174
1173
  dynamicThreshold = circuitData.dynamicThreshold;
1174
+ // the Circuit data for the ceremony setup
1175
+ circuit = {
1176
+ name: circuitData.name,
1177
+ description: circuitData.description,
1178
+ prefix: circuitPrefix,
1179
+ sequencePosition: i + 1,
1180
+ metadata: metadata,
1181
+ files: files,
1182
+ template: template,
1183
+ compiler: compiler,
1184
+ verification: verification,
1185
+ dynamicThreshold: dynamicThreshold,
1186
+ avgTimings: {
1187
+ contributionComputation: 0,
1188
+ fullContribution: 0,
1189
+ verifyCloudFunction: 0
1190
+ },
1191
+ };
1175
1192
  }
1176
1193
  if (data.timeoutMechanismType === "FIXED" /* CeremonyTimeoutType.FIXED */) {
1177
1194
  if (circuitData.fixedTimeWindow <= 0)
1178
1195
  throw new Error("The fixed time window threshold should be > 0.");
1179
1196
  fixedTimeWindow = circuitData.fixedTimeWindow;
1197
+ // the Circuit data for the ceremony setup
1198
+ circuit = {
1199
+ name: circuitData.name,
1200
+ description: circuitData.description,
1201
+ prefix: circuitPrefix,
1202
+ sequencePosition: i + 1,
1203
+ metadata: metadata,
1204
+ files: files,
1205
+ template: template,
1206
+ compiler: compiler,
1207
+ verification: verification,
1208
+ fixedTimeWindow: fixedTimeWindow,
1209
+ avgTimings: {
1210
+ contributionComputation: 0,
1211
+ fullContribution: 0,
1212
+ verifyCloudFunction: 0
1213
+ },
1214
+ };
1180
1215
  }
1181
- // the Circuit data for the ceremony setup
1182
- const circuit = {
1183
- name: circuitData.name,
1184
- description: circuitData.description,
1185
- prefix: circuitPrefix,
1186
- sequencePosition: i + 1,
1187
- metadata: metadata,
1188
- files: files,
1189
- template: template,
1190
- compiler: compiler,
1191
- verification: verification,
1192
- fixedTimeWindow: fixedTimeWindow,
1193
- // dynamicThreshold: dynamicThreshold,
1194
- avgTimings: {
1195
- contributionComputation: 0,
1196
- fullContribution: 0,
1197
- verifyCloudFunction: 0
1198
- },
1199
- };
1200
1216
  circuits.push(circuit);
1201
1217
  // remove the local r1cs download (if used for verifying the config only vs setup)
1202
1218
  if (cleanup)
@@ -2061,55 +2077,27 @@ const verifyCeremony = async (functions, firestore, ceremonyPrefix, outputDirect
2061
2077
  };
2062
2078
 
2063
2079
  /**
2064
- * This function will return the number of public repos of a user
2065
- * @param user <string> The username of the user
2066
- * @returns <number> The number of public repos
2080
+ * This function queries the GitHub API to fetch users statistics
2081
+ * @param user {string} the user uid
2082
+ * @returns {any} the stats from the GitHub API
2067
2083
  */
2068
- const getNumberOfPublicReposGitHub = async (user) => {
2069
- const response = await fetch(`https://api.github.com/user/${user}/repos`, {
2084
+ const getGitHubStats = async (user) => {
2085
+ const response = await fetch(`https://api.github.com/user/${user}`, {
2070
2086
  method: "GET",
2071
2087
  headers: {
2072
2088
  Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`
2073
2089
  }
2074
2090
  });
2075
2091
  if (response.status !== 200)
2076
- throw new Error("It was not possible to retrieve the number of public repositories. Please try again.");
2092
+ throw new Error("It was not possible to retrieve the user's statistic. Please try again.");
2077
2093
  const jsonData = await response.json();
2078
- return jsonData.length;
2079
- };
2080
- /**
2081
- * This function will return the number of followers of a user
2082
- * @param user <string> The username of the user
2083
- * @returns <number> The number of followers
2084
- */
2085
- const getNumberOfFollowersGitHub = async (user) => {
2086
- const response = await fetch(`https://api.github.com/user/${user}/followers`, {
2087
- method: "GET",
2088
- headers: {
2089
- Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`
2090
- }
2091
- });
2092
- if (response.status !== 200)
2093
- throw new Error("It was not possible to retrieve the number of followers. Please try again.");
2094
- const jsonData = await response.json();
2095
- return jsonData.length;
2096
- };
2097
- /**
2098
- * This function will return the number of following of a user
2099
- * @param user <string> The username of the user
2100
- * @returns <number> The number of following users
2101
- */
2102
- const getNumberOfFollowingGitHub = async (user) => {
2103
- const response = await fetch(`https://api.github.com/user/${user}/following`, {
2104
- method: "GET",
2105
- headers: {
2106
- Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`
2107
- }
2108
- });
2109
- if (response.status !== 200)
2110
- throw new Error("It was not possible to retrieve the number of following. Please try again.");
2111
- const jsonData = await response.json();
2112
- return jsonData.length;
2094
+ const data = {
2095
+ following: jsonData.following,
2096
+ followers: jsonData.followers,
2097
+ publicRepos: jsonData.public_repos,
2098
+ avatarUrl: jsonData.avatar_url
2099
+ };
2100
+ return data;
2113
2101
  };
2114
2102
  /**
2115
2103
  * This function will check if the user is reputable enough to be able to use the app
@@ -2117,19 +2105,23 @@ const getNumberOfFollowingGitHub = async (user) => {
2117
2105
  * @param minimumAmountOfFollowing <number> The minimum amount of following the user should have
2118
2106
  * @param minimumAmountOfFollowers <number> The minimum amount of followers the user should have
2119
2107
  * @param minimumAmountOfPublicRepos <number> The minimum amount of public repos the user should have
2120
- * @returns <boolean> True if the user is reputable enough, false otherwise
2108
+ * @returns <any> Return the avatar URL of the user if the user is reputable, false otherwise
2121
2109
  */
2122
2110
  const githubReputation = async (userLogin, minimumAmountOfFollowing, minimumAmountOfFollowers, minimumAmountOfPublicRepos) => {
2123
2111
  if (!process.env.GITHUB_ACCESS_TOKEN)
2124
2112
  throw new Error("The GitHub access token is missing. Please insert a valid token to be used for anti-sybil checks on user registation, and then try again.");
2125
- const following = await getNumberOfFollowingGitHub(userLogin);
2126
- const repos = await getNumberOfPublicReposGitHub(userLogin);
2127
- const followers = await getNumberOfFollowersGitHub(userLogin);
2113
+ const { following, followers, publicRepos, avatarUrl } = await getGitHubStats(userLogin);
2128
2114
  if (following < minimumAmountOfFollowing ||
2129
- repos < minimumAmountOfPublicRepos ||
2115
+ publicRepos < minimumAmountOfPublicRepos ||
2130
2116
  followers < minimumAmountOfFollowers)
2131
- return false;
2132
- return true;
2117
+ return {
2118
+ reputable: false,
2119
+ avatarUrl: ""
2120
+ };
2121
+ return {
2122
+ reputable: true,
2123
+ avatarUrl: avatarUrl
2124
+ };
2133
2125
  };
2134
2126
 
2135
2127
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @module @p0tion/actions
3
- * @version 1.0.4
2
+ * @module @devtion/actions
3
+ * @version 1.0.6
4
4
  * @file A set of actions and helpers for CLI commands
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
@@ -246,6 +246,12 @@ const commonTerms = {
246
246
  verificationStartedAt: "verificationStartedAt"
247
247
  }
248
248
  },
249
+ avatars: {
250
+ name: "avatars",
251
+ fields: {
252
+ avatarUrl: "avatarUrl"
253
+ }
254
+ },
249
255
  ceremonies: {
250
256
  name: "ceremonies",
251
257
  fields: {
@@ -1087,42 +1093,34 @@ const parseCeremonyFile = async (path, cleanup = false) => {
1087
1093
  circuitArtifacts.push({
1088
1094
  artifacts: artifacts
1089
1095
  });
1090
- const r1csPath = artifacts.r1csStoragePath;
1091
- const wasmPath = artifacts.wasmStoragePath;
1092
1096
  // where we storing the r1cs downloaded
1093
1097
  const localR1csPath = `./${circuitData.name}.r1cs`;
1098
+ // where we storing the wasm downloaded
1099
+ const localWasmPath = `./${circuitData.name}.wasm`;
1094
1100
  // check that the artifacts exist in S3
1095
1101
  // we don't need any privileges to download this
1096
1102
  // just the correct region
1097
- const s3 = new clientS3.S3Client({ region: artifacts.region });
1098
- try {
1099
- await s3.send(new clientS3.HeadObjectCommand({
1100
- Bucket: artifacts.bucket,
1101
- Key: r1csPath
1102
- }));
1103
- }
1104
- catch (error) {
1105
- throw new Error(`The r1cs file (${r1csPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`);
1106
- }
1107
- try {
1108
- await s3.send(new clientS3.HeadObjectCommand({
1109
- Bucket: artifacts.bucket,
1110
- Key: wasmPath
1111
- }));
1112
- }
1113
- catch (error) {
1114
- throw new Error(`The wasm file (${wasmPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`);
1115
- }
1103
+ const s3 = new clientS3.S3Client({
1104
+ region: artifacts.region,
1105
+ credentials: undefined
1106
+ });
1116
1107
  // download the r1cs to extract the metadata
1117
1108
  const command = new clientS3.GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.r1csStoragePath });
1118
1109
  const response = await s3.send(command);
1119
1110
  const streamPipeline = util.promisify(stream.pipeline);
1120
1111
  if (response.$metadata.httpStatusCode !== 200)
1121
- throw new Error("There was an error while trying to download the r1cs file. Please check that the file has the correct permissions (public) set.");
1112
+ throw new Error(`There was an error while trying to download the r1cs file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`);
1122
1113
  if (response.Body instanceof stream.Readable)
1123
1114
  await streamPipeline(response.Body, fs.createWriteStream(localR1csPath));
1124
1115
  // extract the metadata from the r1cs
1125
1116
  const metadata = getR1CSInfo(localR1csPath);
1117
+ // download wasm too to ensure it's available
1118
+ const wasmCommand = new clientS3.GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.wasmStoragePath });
1119
+ const wasmResponse = await s3.send(wasmCommand);
1120
+ if (wasmResponse.$metadata.httpStatusCode !== 200)
1121
+ throw new Error(`There was an error while trying to download the wasm file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`);
1122
+ if (wasmResponse.Body instanceof stream.Readable)
1123
+ await streamPipeline(wasmResponse.Body, fs.createWriteStream(localWasmPath));
1126
1124
  // validate that the circuit hash and template links are valid
1127
1125
  const template = circuitData.template;
1128
1126
  const URLMatch = template.source.match(urlPattern);
@@ -1170,35 +1168,53 @@ const parseCeremonyFile = async (path, cleanup = false) => {
1170
1168
  // check that the timeout is provided for the correct configuration
1171
1169
  let dynamicThreshold;
1172
1170
  let fixedTimeWindow;
1171
+ let circuit = {};
1173
1172
  if (data.timeoutMechanismType === "DYNAMIC" /* CeremonyTimeoutType.DYNAMIC */) {
1174
1173
  if (circuitData.dynamicThreshold <= 0)
1175
1174
  throw new Error("The dynamic threshold should be > 0.");
1176
1175
  dynamicThreshold = circuitData.dynamicThreshold;
1176
+ // the Circuit data for the ceremony setup
1177
+ circuit = {
1178
+ name: circuitData.name,
1179
+ description: circuitData.description,
1180
+ prefix: circuitPrefix,
1181
+ sequencePosition: i + 1,
1182
+ metadata: metadata,
1183
+ files: files,
1184
+ template: template,
1185
+ compiler: compiler,
1186
+ verification: verification,
1187
+ dynamicThreshold: dynamicThreshold,
1188
+ avgTimings: {
1189
+ contributionComputation: 0,
1190
+ fullContribution: 0,
1191
+ verifyCloudFunction: 0
1192
+ },
1193
+ };
1177
1194
  }
1178
1195
  if (data.timeoutMechanismType === "FIXED" /* CeremonyTimeoutType.FIXED */) {
1179
1196
  if (circuitData.fixedTimeWindow <= 0)
1180
1197
  throw new Error("The fixed time window threshold should be > 0.");
1181
1198
  fixedTimeWindow = circuitData.fixedTimeWindow;
1199
+ // the Circuit data for the ceremony setup
1200
+ circuit = {
1201
+ name: circuitData.name,
1202
+ description: circuitData.description,
1203
+ prefix: circuitPrefix,
1204
+ sequencePosition: i + 1,
1205
+ metadata: metadata,
1206
+ files: files,
1207
+ template: template,
1208
+ compiler: compiler,
1209
+ verification: verification,
1210
+ fixedTimeWindow: fixedTimeWindow,
1211
+ avgTimings: {
1212
+ contributionComputation: 0,
1213
+ fullContribution: 0,
1214
+ verifyCloudFunction: 0
1215
+ },
1216
+ };
1182
1217
  }
1183
- // the Circuit data for the ceremony setup
1184
- const circuit = {
1185
- name: circuitData.name,
1186
- description: circuitData.description,
1187
- prefix: circuitPrefix,
1188
- sequencePosition: i + 1,
1189
- metadata: metadata,
1190
- files: files,
1191
- template: template,
1192
- compiler: compiler,
1193
- verification: verification,
1194
- fixedTimeWindow: fixedTimeWindow,
1195
- // dynamicThreshold: dynamicThreshold,
1196
- avgTimings: {
1197
- contributionComputation: 0,
1198
- fullContribution: 0,
1199
- verifyCloudFunction: 0
1200
- },
1201
- };
1202
1218
  circuits.push(circuit);
1203
1219
  // remove the local r1cs download (if used for verifying the config only vs setup)
1204
1220
  if (cleanup)
@@ -2063,55 +2079,27 @@ const verifyCeremony = async (functions, firestore$1, ceremonyPrefix, outputDire
2063
2079
  };
2064
2080
 
2065
2081
  /**
2066
- * This function will return the number of public repos of a user
2067
- * @param user <string> The username of the user
2068
- * @returns <number> The number of public repos
2082
+ * This function queries the GitHub API to fetch users statistics
2083
+ * @param user {string} the user uid
2084
+ * @returns {any} the stats from the GitHub API
2069
2085
  */
2070
- const getNumberOfPublicReposGitHub = async (user) => {
2071
- const response = await fetch(`https://api.github.com/user/${user}/repos`, {
2086
+ const getGitHubStats = async (user) => {
2087
+ const response = await fetch(`https://api.github.com/user/${user}`, {
2072
2088
  method: "GET",
2073
2089
  headers: {
2074
2090
  Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`
2075
2091
  }
2076
2092
  });
2077
2093
  if (response.status !== 200)
2078
- throw new Error("It was not possible to retrieve the number of public repositories. Please try again.");
2094
+ throw new Error("It was not possible to retrieve the user's statistic. Please try again.");
2079
2095
  const jsonData = await response.json();
2080
- return jsonData.length;
2081
- };
2082
- /**
2083
- * This function will return the number of followers of a user
2084
- * @param user <string> The username of the user
2085
- * @returns <number> The number of followers
2086
- */
2087
- const getNumberOfFollowersGitHub = async (user) => {
2088
- const response = await fetch(`https://api.github.com/user/${user}/followers`, {
2089
- method: "GET",
2090
- headers: {
2091
- Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`
2092
- }
2093
- });
2094
- if (response.status !== 200)
2095
- throw new Error("It was not possible to retrieve the number of followers. Please try again.");
2096
- const jsonData = await response.json();
2097
- return jsonData.length;
2098
- };
2099
- /**
2100
- * This function will return the number of following of a user
2101
- * @param user <string> The username of the user
2102
- * @returns <number> The number of following users
2103
- */
2104
- const getNumberOfFollowingGitHub = async (user) => {
2105
- const response = await fetch(`https://api.github.com/user/${user}/following`, {
2106
- method: "GET",
2107
- headers: {
2108
- Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN}`
2109
- }
2110
- });
2111
- if (response.status !== 200)
2112
- throw new Error("It was not possible to retrieve the number of following. Please try again.");
2113
- const jsonData = await response.json();
2114
- return jsonData.length;
2096
+ const data = {
2097
+ following: jsonData.following,
2098
+ followers: jsonData.followers,
2099
+ publicRepos: jsonData.public_repos,
2100
+ avatarUrl: jsonData.avatar_url
2101
+ };
2102
+ return data;
2115
2103
  };
2116
2104
  /**
2117
2105
  * This function will check if the user is reputable enough to be able to use the app
@@ -2119,19 +2107,23 @@ const getNumberOfFollowingGitHub = async (user) => {
2119
2107
  * @param minimumAmountOfFollowing <number> The minimum amount of following the user should have
2120
2108
  * @param minimumAmountOfFollowers <number> The minimum amount of followers the user should have
2121
2109
  * @param minimumAmountOfPublicRepos <number> The minimum amount of public repos the user should have
2122
- * @returns <boolean> True if the user is reputable enough, false otherwise
2110
+ * @returns <any> Return the avatar URL of the user if the user is reputable, false otherwise
2123
2111
  */
2124
2112
  const githubReputation = async (userLogin, minimumAmountOfFollowing, minimumAmountOfFollowers, minimumAmountOfPublicRepos) => {
2125
2113
  if (!process.env.GITHUB_ACCESS_TOKEN)
2126
2114
  throw new Error("The GitHub access token is missing. Please insert a valid token to be used for anti-sybil checks on user registation, and then try again.");
2127
- const following = await getNumberOfFollowingGitHub(userLogin);
2128
- const repos = await getNumberOfPublicReposGitHub(userLogin);
2129
- const followers = await getNumberOfFollowersGitHub(userLogin);
2115
+ const { following, followers, publicRepos, avatarUrl } = await getGitHubStats(userLogin);
2130
2116
  if (following < minimumAmountOfFollowing ||
2131
- repos < minimumAmountOfPublicRepos ||
2117
+ publicRepos < minimumAmountOfPublicRepos ||
2132
2118
  followers < minimumAmountOfFollowers)
2133
- return false;
2134
- return true;
2119
+ return {
2120
+ reputable: false,
2121
+ avatarUrl: ""
2122
+ };
2123
+ return {
2124
+ reputable: true,
2125
+ avatarUrl: avatarUrl
2126
+ };
2135
2127
  };
2136
2128
 
2137
2129
  /**
@@ -98,6 +98,12 @@ export declare const commonTerms: {
98
98
  verificationStartedAt: string;
99
99
  };
100
100
  };
101
+ avatars: {
102
+ name: string;
103
+ fields: {
104
+ avatarUrl: string;
105
+ };
106
+ };
101
107
  ceremonies: {
102
108
  name: string;
103
109
  fields: {
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/helpers/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,sBAAsB,+CAA+C,CAAA;AAElF,eAAO,MAAM,mBAAmB,6BAA6B,CAAA;AAE7D,eAAO,MAAM,gBAAgB,UAAU,CAAA;AAEvC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,eAAO,MAAM,eAAe,UAAU,CAAA;AAEtC,eAAO,MAAM,sBAAsB,UAAU,CAAA;AAE7C,eAAO,MAAM,sBAAsB,SAAS,CAAA;AAE5C,eAAO,MAAM,4BAA4B,aAAa,CAAA;AAEtD,eAAO,MAAM,cAAc,sBAAsB,CAAA;AAEjD,eAAO,MAAM,yBAAyB,iBAAiB,CAAA;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ChC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;GA6G5B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuHvB,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/helpers/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,sBAAsB,+CAA+C,CAAA;AAElF,eAAO,MAAM,mBAAmB,6BAA6B,CAAA;AAE7D,eAAO,MAAM,gBAAgB,UAAU,CAAA;AAEvC,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,eAAO,MAAM,eAAe,UAAU,CAAA;AAEtC,eAAO,MAAM,sBAAsB,UAAU,CAAA;AAE7C,eAAO,MAAM,sBAAsB,SAAS,CAAA;AAE5C,eAAO,MAAM,4BAA4B,aAAa,CAAA;AAEtD,eAAO,MAAM,cAAc,sBAAsB,CAAA;AAEjD,eAAO,MAAM,yBAAyB,iBAAiB,CAAA;AAEvD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ChC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;GA6G5B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6HvB,CAAA"}
@@ -4,7 +4,7 @@
4
4
  * @param minimumAmountOfFollowing <number> The minimum amount of following the user should have
5
5
  * @param minimumAmountOfFollowers <number> The minimum amount of followers the user should have
6
6
  * @param minimumAmountOfPublicRepos <number> The minimum amount of public repos the user should have
7
- * @returns <boolean> True if the user is reputable enough, false otherwise
7
+ * @returns <any> Return the avatar URL of the user if the user is reputable, false otherwise
8
8
  */
9
- export declare const githubReputation: (userLogin: string, minimumAmountOfFollowing: number, minimumAmountOfFollowers: number, minimumAmountOfPublicRepos: number) => Promise<boolean>;
9
+ export declare const githubReputation: (userLogin: string, minimumAmountOfFollowing: number, minimumAmountOfFollowers: number, minimumAmountOfPublicRepos: number) => Promise<any>;
10
10
  //# sourceMappingURL=security.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../../src/helpers/security.ts"],"names":[],"mappings":"AAwDA;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,cACd,MAAM,4BACS,MAAM,4BACN,MAAM,8BACJ,MAAM,KACnC,QAAQ,OAAO,CAgBjB,CAAA"}
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../../src/helpers/security.ts"],"names":[],"mappings":"AA8BA;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,cACd,MAAM,4BACS,MAAM,4BACN,MAAM,8BACJ,MAAM,KACnC,QAAQ,GAAG,CAsBb,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/helpers/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAW,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AAErC,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EACH,eAAe,EACf,YAAY,EAGZ,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EAGpB,MAAM,gBAAgB,CAAA;AAmBvB;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,SAAgB,MAAM,YAAW,OAAO,KAAW,QAAQ,iBAAiB,CA4MzG,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,iBAAkB,MAAM,UAAU,MAAM,KAAG,MAgBtF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,gBAAiB,MAAM,WAAW,MAAM,WAUxF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,aAAc,MAAM,KAAG,MASlD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,wBAAyB,MAAM,KAAG,MACH,CAAA;AAElE;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,QAAS,MAAM,KAAG,MAEsC,CAAA;AAElF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,cAAsE,CAAA;AAEtG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,aAC3B,MAAM,oBAAoB,CAAC,oBACnB,MAAM,KACzB,oBAYF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,cAAe,MAAM,WAAW,OAAO,KAAG,MAC1B,CAAA;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,sCAAsC,sBAC5B,SAAS,YAClB,MAAM,oBAAoB,CAAC,cACzB,MAAM,iBACH,MAAM,gBACP,OAAO,KACtB,QAAQ,MAAM,oBAAoB,CAAC,CAmCrC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,0CAA0C,0BAC5B,MAAM,gBACf,MAAM,gBACN,OAAO,WAImF,CAAA;AAE5G;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qCAAqC,sBAC3B,SAAS,YAClB,MAAM,oBAAoB,CAAC,cACzB,MAAM,iBACH,MAAM,4BACK,MAAM,YAAY,CAAC,yBACtB,MAAM,gBACf,MAAM,gBACN,OAAO,KACtB,QAAQ,MAAM,CA2DhB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,aAAc,MAAM,UAAS,QAAQ,aAAa,CAAC,OAAO,CAAC,KAAY,MAQvG,CAAA;AAEN;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,kBACX,MAAM,UACb,MAAM,UACN,MAAM,YACJ,YAAY,KACvB,MAYF,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,sBAAuB,MAAM,KAAG,eA0IvD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,WAAY,MAAM,KAAG,MAA0D,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/helpers/utils.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAW,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AAErC,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEzC,OAAO,EACH,eAAe,EACf,YAAY,EAGZ,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EAGpB,MAAM,gBAAgB,CAAA;AAmBvB;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,SAAgB,MAAM,YAAW,OAAO,KAAW,QAAQ,iBAAiB,CA+NzG,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,+BAA+B,iBAAkB,MAAM,UAAU,MAAM,KAAG,MAgBtF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oCAAoC,gBAAiB,MAAM,WAAW,MAAM,WAUxF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,aAAc,MAAM,KAAG,MASlD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,wBAAyB,MAAM,KAAG,MACH,CAAA;AAElE;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,QAAS,MAAM,KAAG,MAEsC,CAAA;AAElF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,cAAsE,CAAA;AAEtG;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,aAC3B,MAAM,oBAAoB,CAAC,oBACnB,MAAM,KACzB,oBAYF,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,cAAe,MAAM,WAAW,OAAO,KAAG,MAC1B,CAAA;AAEjD;;;;;;;;GAQG;AACH,eAAO,MAAM,sCAAsC,sBAC5B,SAAS,YAClB,MAAM,oBAAoB,CAAC,cACzB,MAAM,iBACH,MAAM,gBACP,OAAO,KACtB,QAAQ,MAAM,oBAAoB,CAAC,CAmCrC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,0CAA0C,0BAC5B,MAAM,gBACf,MAAM,gBACN,OAAO,WAImF,CAAA;AAE5G;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qCAAqC,sBAC3B,SAAS,YAClB,MAAM,oBAAoB,CAAC,cACzB,MAAM,iBACH,MAAM,4BACK,MAAM,YAAY,CAAC,yBACtB,MAAM,gBACf,MAAM,gBACN,OAAO,KACtB,QAAQ,MAAM,CA2DhB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,aAAc,MAAM,UAAS,QAAQ,aAAa,CAAC,OAAO,CAAC,KAAY,MAQvG,CAAA;AAEN;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,kBACX,MAAM,UACb,MAAM,UACN,MAAM,YACJ,YAAY,KACvB,MAYF,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,sBAAuB,MAAM,KAAG,eA0IvD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,WAAY,MAAM,KAAG,MAA0D,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtion/actions",
3
- "version": "0.0.0-270e9e0",
3
+ "version": "0.0.0-56491a8",
4
4
  "description": "A set of actions and helpers for CLI commands",
5
5
  "repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
6
6
  "homepage": "https://github.com/privacy-scaling-explorations/p0tion",
@@ -83,5 +83,5 @@
83
83
  "publishConfig": {
84
84
  "access": "public"
85
85
  },
86
- "gitHead": "558cd8e1ece3f6f3cde816d3bb0b88fea90a86a9"
86
+ "gitHead": "29b556076a3424c9aaf3a5a35b40df8520fa2217"
87
87
  }
@@ -217,6 +217,12 @@ export const commonTerms = {
217
217
  verificationStartedAt: "verificationStartedAt"
218
218
  }
219
219
  },
220
+ avatars: {
221
+ name: "avatars",
222
+ fields: {
223
+ avatarUrl: "avatarUrl"
224
+ }
225
+ },
220
226
  ceremonies: {
221
227
  name: "ceremonies",
222
228
  fields: {
@@ -1,45 +1,12 @@
1
1
  import fetch from "@adobe/node-fetch-retry"
2
+
2
3
  /**
3
- * This function will return the number of public repos of a user
4
- * @param user <string> The username of the user
5
- * @returns <number> The number of public repos
6
- */
7
- const getNumberOfPublicReposGitHub = async (user: string): Promise<number> => {
8
- const response = await fetch(`https://api.github.com/user/${user}/repos`, {
9
- method: "GET",
10
- headers: {
11
- Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN!}`
12
- }
13
- })
14
- if (response.status !== 200)
15
- throw new Error("It was not possible to retrieve the number of public repositories. Please try again.")
16
- const jsonData: any = await response.json()
17
- return jsonData.length
18
- }
19
- /**
20
- * This function will return the number of followers of a user
21
- * @param user <string> The username of the user
22
- * @returns <number> The number of followers
23
- */
24
- const getNumberOfFollowersGitHub = async (user: string): Promise<number> => {
25
- const response = await fetch(`https://api.github.com/user/${user}/followers`, {
26
- method: "GET",
27
- headers: {
28
- Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN!}`
29
- }
30
- })
31
- if (response.status !== 200)
32
- throw new Error("It was not possible to retrieve the number of followers. Please try again.")
33
- const jsonData: any = await response.json()
34
- return jsonData.length
35
- }
36
- /**
37
- * This function will return the number of following of a user
38
- * @param user <string> The username of the user
39
- * @returns <number> The number of following users
4
+ * This function queries the GitHub API to fetch users statistics
5
+ * @param user {string} the user uid
6
+ * @returns {any} the stats from the GitHub API
40
7
  */
41
- const getNumberOfFollowingGitHub = async (user: string): Promise<number> => {
42
- const response = await fetch(`https://api.github.com/user/${user}/following`, {
8
+ const getGitHubStats = async (user: string): Promise<any> => {
9
+ const response = await fetch(`https://api.github.com/user/${user}`, {
43
10
  method: "GET",
44
11
  headers: {
45
12
  Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN!}`
@@ -47,11 +14,18 @@ const getNumberOfFollowingGitHub = async (user: string): Promise<number> => {
47
14
  })
48
15
 
49
16
  if (response.status !== 200)
50
- throw new Error("It was not possible to retrieve the number of following. Please try again.")
17
+ throw new Error("It was not possible to retrieve the user's statistic. Please try again.")
51
18
 
52
19
  const jsonData: any = await response.json()
53
20
 
54
- return jsonData.length
21
+ const data = {
22
+ following: jsonData.following,
23
+ followers: jsonData.followers,
24
+ publicRepos: jsonData.public_repos,
25
+ avatarUrl: jsonData.avatar_url
26
+ }
27
+
28
+ return data
55
29
  }
56
30
 
57
31
  /**
@@ -60,27 +34,33 @@ const getNumberOfFollowingGitHub = async (user: string): Promise<number> => {
60
34
  * @param minimumAmountOfFollowing <number> The minimum amount of following the user should have
61
35
  * @param minimumAmountOfFollowers <number> The minimum amount of followers the user should have
62
36
  * @param minimumAmountOfPublicRepos <number> The minimum amount of public repos the user should have
63
- * @returns <boolean> True if the user is reputable enough, false otherwise
37
+ * @returns <any> Return the avatar URL of the user if the user is reputable, false otherwise
64
38
  */
65
39
  export const githubReputation = async (
66
40
  userLogin: string,
67
41
  minimumAmountOfFollowing: number,
68
42
  minimumAmountOfFollowers: number,
69
43
  minimumAmountOfPublicRepos: number
70
- ): Promise<boolean> => {
44
+ ): Promise<any> => {
71
45
  if (!process.env.GITHUB_ACCESS_TOKEN)
72
46
  throw new Error(
73
47
  "The GitHub access token is missing. Please insert a valid token to be used for anti-sybil checks on user registation, and then try again."
74
48
  )
75
- const following = await getNumberOfFollowingGitHub(userLogin)
76
- const repos = await getNumberOfPublicReposGitHub(userLogin)
77
- const followers = await getNumberOfFollowersGitHub(userLogin)
49
+
50
+ const { following, followers, publicRepos, avatarUrl } = await getGitHubStats(userLogin)
78
51
 
79
52
  if (
80
53
  following < minimumAmountOfFollowing ||
81
- repos < minimumAmountOfPublicRepos ||
54
+ publicRepos < minimumAmountOfPublicRepos ||
82
55
  followers < minimumAmountOfFollowers
83
56
  )
84
- return false
85
- return true
57
+ return {
58
+ reputable: false,
59
+ avatarUrl: ""
60
+ }
61
+
62
+ return {
63
+ reputable: true,
64
+ avatarUrl: avatarUrl
65
+ }
86
66
  }
@@ -87,34 +87,19 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
87
87
  circuitArtifacts.push({
88
88
  artifacts: artifacts
89
89
  })
90
- const r1csPath = artifacts.r1csStoragePath
91
- const wasmPath = artifacts.wasmStoragePath
92
90
 
93
91
  // where we storing the r1cs downloaded
94
92
  const localR1csPath = `./${circuitData.name}.r1cs`
93
+ // where we storing the wasm downloaded
94
+ const localWasmPath = `./${circuitData.name}.wasm`
95
95
 
96
96
  // check that the artifacts exist in S3
97
97
  // we don't need any privileges to download this
98
98
  // just the correct region
99
- const s3 = new S3Client({region: artifacts.region})
100
-
101
- try {
102
- await s3.send(new HeadObjectCommand({
103
- Bucket: artifacts.bucket,
104
- Key: r1csPath
105
- }))
106
- } catch (error: any) {
107
- throw new Error(`The r1cs file (${r1csPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`)
108
- }
109
-
110
- try {
111
- await s3.send(new HeadObjectCommand({
112
- Bucket: artifacts.bucket,
113
- Key: wasmPath
114
- }))
115
- } catch (error: any) {
116
- throw new Error(`The wasm file (${wasmPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`)
117
- }
99
+ const s3 = new S3Client({
100
+ region: artifacts.region,
101
+ credentials: undefined
102
+ })
118
103
 
119
104
  // download the r1cs to extract the metadata
120
105
  const command = new GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.r1csStoragePath })
@@ -122,7 +107,7 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
122
107
  const streamPipeline = promisify(pipeline)
123
108
 
124
109
  if (response.$metadata.httpStatusCode !== 200)
125
- throw new Error("There was an error while trying to download the r1cs file. Please check that the file has the correct permissions (public) set.")
110
+ throw new Error(`There was an error while trying to download the r1cs file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`)
126
111
 
127
112
  if (response.Body instanceof Readable)
128
113
  await streamPipeline(response.Body, fs.createWriteStream(localR1csPath))
@@ -130,6 +115,16 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
130
115
  // extract the metadata from the r1cs
131
116
  const metadata = getR1CSInfo(localR1csPath)
132
117
 
118
+ // download wasm too to ensure it's available
119
+ const wasmCommand = new GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.wasmStoragePath })
120
+ const wasmResponse = await s3.send(wasmCommand)
121
+
122
+ if (wasmResponse.$metadata.httpStatusCode !== 200)
123
+ throw new Error(`There was an error while trying to download the wasm file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`)
124
+
125
+ if (wasmResponse.Body instanceof Readable)
126
+ await streamPipeline(wasmResponse.Body, fs.createWriteStream(localWasmPath))
127
+
133
128
  // validate that the circuit hash and template links are valid
134
129
  const template = circuitData.template
135
130