Skip to content

Commit

Permalink
External extensions tweaks (#203)
Browse files Browse the repository at this point in the history
  • Loading branch information
carletex authored Jan 22, 2025
1 parent 13bf6a9 commit 1572e5a
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 84 deletions.
5 changes: 5 additions & 0 deletions .changeset/mighty-singers-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-eth": patch
---

Add trusted GitHub organizations for extensions
31 changes: 0 additions & 31 deletions src/curated-extensions.ts

This file was deleted.

72 changes: 71 additions & 1 deletion src/utils/external-extensions.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,39 @@
import fs from "fs";
import path from "path";
import * as https from "https";
import { fileURLToPath } from "url";
import { ExternalExtension, RawOptions, SolidityFramework } from "../types";
import { CURATED_EXTENSIONS } from "../curated-extensions";
import curatedExtension from "../extensions.json";
import { SOLIDITY_FRAMEWORKS } from "./consts";

type ExtensionJSON = {
extensionFlagValue: string;
repository: string;
branch?: string;
// fields usefull for scaffoldeth.io
description: string;
version?: string; // if not present we default to latest
name?: string; // human redable name, if not present we default to branch or extensionFlagValue on UI
};

const TRUSTED_GITHUB_ORGANIZATIONS = ["scaffold-eth", "buidlguidl"];

const extensions: ExtensionJSON[] = curatedExtension;
const CURATED_EXTENSIONS = extensions.reduce<Record<string, ExternalExtension>>((acc, ext) => {
if (!ext.repository) {
throw new Error(`Extension must have 'repository': ${JSON.stringify(ext)}`);
}
if (!ext.extensionFlagValue) {
throw new Error(`Extension must have 'extensionFlagValue': ${JSON.stringify(ext)}`);
}

acc[ext.extensionFlagValue] = {
repository: ext.repository,
branch: ext.branch,
};
return acc;
}, {});

function deconstructGithubUrl(url: string) {
const urlParts = url.split("/");
const ownerName = urlParts[3];
Expand All @@ -14,6 +43,47 @@ function deconstructGithubUrl(url: string) {
return { ownerName, repoName, branch };
}

export const validateExternalExtension = async (
extensionName: string,
dev: boolean,
): Promise<{ repository: string; branch?: string; isTrusted: boolean } | string> => {
if (dev) {
// Check externalExtensions/${extensionName} exists
try {
const currentFileUrl = import.meta.url;
const externalExtensionsDirectory = path.resolve(
decodeURI(fileURLToPath(currentFileUrl)),
"../../externalExtensions",
);
await fs.promises.access(`${externalExtensionsDirectory}/${extensionName}`);
} catch {
throw new Error(`Extension not found in "externalExtensions/${extensionName}"`);
}

return extensionName;
}

const { githubUrl, githubBranchUrl, branch, owner } = getDataFromExternalExtensionArgument(extensionName);
const isTrusted = TRUSTED_GITHUB_ORGANIZATIONS.includes(owner.toLowerCase()) || !!CURATED_EXTENSIONS[extensionName];

// Check if repository exists
await new Promise((resolve, reject) => {
https
.get(githubBranchUrl, res => {
if (res.statusCode !== 200) {
reject(new Error(`Extension not found: ${githubUrl}`));
} else {
resolve(null);
}
})
.on("error", err => {
reject(err);
});
});

return { repository: githubUrl, branch, isTrusted };
};

// Gets the data from the argument passed to the `--extension` option.
export const getDataFromExternalExtensionArgument = (externalExtension: string) => {
if (CURATED_EXTENSIONS[externalExtension]) {
Expand Down
57 changes: 5 additions & 52 deletions src/utils/parse-arguments-into-options.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,11 @@
import type { Args, ExternalExtension, SolidityFramework, RawOptions, SolidityFrameworkChoices } from "../types";
import type { Args, SolidityFramework, RawOptions, SolidityFrameworkChoices } from "../types";
import arg from "arg";
import * as https from "https";
import {
getDataFromExternalExtensionArgument,
getSolidityFrameworkDirsFromExternalExtension,
} from "./external-extensions";
import { getSolidityFrameworkDirsFromExternalExtension, validateExternalExtension } from "./external-extensions";
import chalk from "chalk";
import { CURATED_EXTENSIONS } from "../curated-extensions";
import { SOLIDITY_FRAMEWORKS } from "./consts";
import { validateFoundryUp } from "./system-validation";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { validateNpmName } from "./validate-name";

const validateExternalExtension = async (
extensionName: string,
dev: boolean,
): Promise<{ repository: string; branch?: string } | string> => {
if (dev) {
// Check externalExtensions/${extensionName} exists
try {
const currentFileUrl = import.meta.url;
const externalExtensionsDirectory = path.resolve(
decodeURI(fileURLToPath(currentFileUrl)),
"../../externalExtensions",
);
await fs.promises.access(`${externalExtensionsDirectory}/${extensionName}`);
} catch {
throw new Error(`Extension not found in "externalExtensions/${extensionName}"`);
}

return extensionName;
}

const { githubUrl, githubBranchUrl, branch } = getDataFromExternalExtensionArgument(extensionName);

// Check if repository exists
await new Promise((resolve, reject) => {
https
.get(githubBranchUrl, res => {
if (res.statusCode !== 200) {
reject(new Error(`Extension not found: ${githubUrl}`));
} else {
resolve(null);
}
})
.on("error", err => {
reject(err);
});
});

return { repository: githubUrl, branch };
};

// TODO update smartContractFramework code with general extensions
export async function parseArgumentsIntoOptions(
rawArgs: Args,
Expand Down Expand Up @@ -92,11 +44,12 @@ export async function parseArgumentsIntoOptions(
// ToDo. Allow multiple
const extension = extensionName ? await validateExternalExtension(extensionName, dev) : null;

if (!dev && extension && !CURATED_EXTENSIONS[args["--extension"] as string]) {
// if dev mode, extension would be a string
if (extension && typeof extension === "object" && !extension.isTrusted) {
console.log(
chalk.yellow(
` You are using a third-party extension. Make sure you trust the source of ${chalk.yellow.bold(
(extension as ExternalExtension).repository,
extension.repository,
)}\n`,
),
);
Expand Down

0 comments on commit 1572e5a

Please sign in to comment.