Skip to content

Commit 1572e5a

Browse files
authored
External extensions tweaks (#203)
1 parent 13bf6a9 commit 1572e5a

File tree

4 files changed

+81
-84
lines changed

4 files changed

+81
-84
lines changed

.changeset/mighty-singers-burn.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"create-eth": patch
3+
---
4+
5+
Add trusted GitHub organizations for extensions

src/curated-extensions.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/utils/external-extensions.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
import fs from "fs";
22
import path from "path";
3+
import * as https from "https";
34
import { fileURLToPath } from "url";
45
import { ExternalExtension, RawOptions, SolidityFramework } from "../types";
5-
import { CURATED_EXTENSIONS } from "../curated-extensions";
6+
import curatedExtension from "../extensions.json";
67
import { SOLIDITY_FRAMEWORKS } from "./consts";
78

9+
type ExtensionJSON = {
10+
extensionFlagValue: string;
11+
repository: string;
12+
branch?: string;
13+
// fields usefull for scaffoldeth.io
14+
description: string;
15+
version?: string; // if not present we default to latest
16+
name?: string; // human redable name, if not present we default to branch or extensionFlagValue on UI
17+
};
18+
19+
const TRUSTED_GITHUB_ORGANIZATIONS = ["scaffold-eth", "buidlguidl"];
20+
21+
const extensions: ExtensionJSON[] = curatedExtension;
22+
const CURATED_EXTENSIONS = extensions.reduce<Record<string, ExternalExtension>>((acc, ext) => {
23+
if (!ext.repository) {
24+
throw new Error(`Extension must have 'repository': ${JSON.stringify(ext)}`);
25+
}
26+
if (!ext.extensionFlagValue) {
27+
throw new Error(`Extension must have 'extensionFlagValue': ${JSON.stringify(ext)}`);
28+
}
29+
30+
acc[ext.extensionFlagValue] = {
31+
repository: ext.repository,
32+
branch: ext.branch,
33+
};
34+
return acc;
35+
}, {});
36+
837
function deconstructGithubUrl(url: string) {
938
const urlParts = url.split("/");
1039
const ownerName = urlParts[3];
@@ -14,6 +43,47 @@ function deconstructGithubUrl(url: string) {
1443
return { ownerName, repoName, branch };
1544
}
1645

46+
export const validateExternalExtension = async (
47+
extensionName: string,
48+
dev: boolean,
49+
): Promise<{ repository: string; branch?: string; isTrusted: boolean } | string> => {
50+
if (dev) {
51+
// Check externalExtensions/${extensionName} exists
52+
try {
53+
const currentFileUrl = import.meta.url;
54+
const externalExtensionsDirectory = path.resolve(
55+
decodeURI(fileURLToPath(currentFileUrl)),
56+
"../../externalExtensions",
57+
);
58+
await fs.promises.access(`${externalExtensionsDirectory}/${extensionName}`);
59+
} catch {
60+
throw new Error(`Extension not found in "externalExtensions/${extensionName}"`);
61+
}
62+
63+
return extensionName;
64+
}
65+
66+
const { githubUrl, githubBranchUrl, branch, owner } = getDataFromExternalExtensionArgument(extensionName);
67+
const isTrusted = TRUSTED_GITHUB_ORGANIZATIONS.includes(owner.toLowerCase()) || !!CURATED_EXTENSIONS[extensionName];
68+
69+
// Check if repository exists
70+
await new Promise((resolve, reject) => {
71+
https
72+
.get(githubBranchUrl, res => {
73+
if (res.statusCode !== 200) {
74+
reject(new Error(`Extension not found: ${githubUrl}`));
75+
} else {
76+
resolve(null);
77+
}
78+
})
79+
.on("error", err => {
80+
reject(err);
81+
});
82+
});
83+
84+
return { repository: githubUrl, branch, isTrusted };
85+
};
86+
1787
// Gets the data from the argument passed to the `--extension` option.
1888
export const getDataFromExternalExtensionArgument = (externalExtension: string) => {
1989
if (CURATED_EXTENSIONS[externalExtension]) {

src/utils/parse-arguments-into-options.ts

Lines changed: 5 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,11 @@
1-
import type { Args, ExternalExtension, SolidityFramework, RawOptions, SolidityFrameworkChoices } from "../types";
1+
import type { Args, SolidityFramework, RawOptions, SolidityFrameworkChoices } from "../types";
22
import arg from "arg";
3-
import * as https from "https";
4-
import {
5-
getDataFromExternalExtensionArgument,
6-
getSolidityFrameworkDirsFromExternalExtension,
7-
} from "./external-extensions";
3+
import { getSolidityFrameworkDirsFromExternalExtension, validateExternalExtension } from "./external-extensions";
84
import chalk from "chalk";
9-
import { CURATED_EXTENSIONS } from "../curated-extensions";
105
import { SOLIDITY_FRAMEWORKS } from "./consts";
116
import { validateFoundryUp } from "./system-validation";
12-
import fs from "fs";
13-
import path from "path";
14-
import { fileURLToPath } from "url";
157
import { validateNpmName } from "./validate-name";
168

17-
const validateExternalExtension = async (
18-
extensionName: string,
19-
dev: boolean,
20-
): Promise<{ repository: string; branch?: string } | string> => {
21-
if (dev) {
22-
// Check externalExtensions/${extensionName} exists
23-
try {
24-
const currentFileUrl = import.meta.url;
25-
const externalExtensionsDirectory = path.resolve(
26-
decodeURI(fileURLToPath(currentFileUrl)),
27-
"../../externalExtensions",
28-
);
29-
await fs.promises.access(`${externalExtensionsDirectory}/${extensionName}`);
30-
} catch {
31-
throw new Error(`Extension not found in "externalExtensions/${extensionName}"`);
32-
}
33-
34-
return extensionName;
35-
}
36-
37-
const { githubUrl, githubBranchUrl, branch } = getDataFromExternalExtensionArgument(extensionName);
38-
39-
// Check if repository exists
40-
await new Promise((resolve, reject) => {
41-
https
42-
.get(githubBranchUrl, res => {
43-
if (res.statusCode !== 200) {
44-
reject(new Error(`Extension not found: ${githubUrl}`));
45-
} else {
46-
resolve(null);
47-
}
48-
})
49-
.on("error", err => {
50-
reject(err);
51-
});
52-
});
53-
54-
return { repository: githubUrl, branch };
55-
};
56-
579
// TODO update smartContractFramework code with general extensions
5810
export async function parseArgumentsIntoOptions(
5911
rawArgs: Args,
@@ -92,11 +44,12 @@ export async function parseArgumentsIntoOptions(
9244
// ToDo. Allow multiple
9345
const extension = extensionName ? await validateExternalExtension(extensionName, dev) : null;
9446

95-
if (!dev && extension && !CURATED_EXTENSIONS[args["--extension"] as string]) {
47+
// if dev mode, extension would be a string
48+
if (extension && typeof extension === "object" && !extension.isTrusted) {
9649
console.log(
9750
chalk.yellow(
9851
` You are using a third-party extension. Make sure you trust the source of ${chalk.yellow.bold(
99-
(extension as ExternalExtension).repository,
52+
extension.repository,
10053
)}\n`,
10154
),
10255
);

0 commit comments

Comments
 (0)