Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nmattia committed Nov 23, 2023
1 parent 018ce48 commit eefcfd1
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ test("Should not issue delegation when /.well-known/ii-alternative-origins has t
'{"alternativeOrigins":["https://a0.com", "https://a1.com", "https://a2.com", "https://a3.com", "https://a4.com", "https://a5.com", "https://a6.com", "https://a7.com", "https://a8.com", "https://a9.com", "https://a10.com"]}',
"certified"
);
await niceDemoAppView.setDerivationOrigin(TEST_APP_CANONICAL_URL);
await niceDemoAppView.setDerivationOrigin(await TEST_APP_CANONICAL_URL());
expect(await niceDemoAppView.getPrincipal()).toBe("2vxsx-fae");
await niceDemoAppView.signin();

Expand Down Expand Up @@ -70,7 +70,7 @@ test("Should not follow redirect returned by /.well-known/ii-alternative-origins
'{"alternativeOrigins":["https://evil.com"]}',
"redirect"
);
await niceDemoAppView.setDerivationOrigin(TEST_APP_CANONICAL_URL);
await niceDemoAppView.setDerivationOrigin(await TEST_APP_CANONICAL_URL());
expect(await niceDemoAppView.getPrincipal()).toBe("2vxsx-fae");
await niceDemoAppView.signin();

Expand Down Expand Up @@ -108,7 +108,9 @@ test("Should fetch /.well-known/ii-alternative-origins using the non-raw url", a
`{"alternativeOrigins":["${TEST_APP_NICE_URL}"]}`,
"certified"
);
await niceDemoAppView.setDerivationOrigin(TEST_APP_CANONICAL_URL_RAW);
await niceDemoAppView.setDerivationOrigin(
await TEST_APP_CANONICAL_URL_RAW()
);
expect(await niceDemoAppView.getPrincipal()).toBe("2vxsx-fae");
await niceDemoAppView.signin();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ test("Should not issue delegation when derivationOrigin is missing from /.well-k
await niceDemoAppView.open(TEST_APP_NICE_URL, II_URL);
await niceDemoAppView.waitForDisplay();
await niceDemoAppView.resetAlternativeOrigins();
await niceDemoAppView.setDerivationOrigin(TEST_APP_CANONICAL_URL);
await niceDemoAppView.setDerivationOrigin(await TEST_APP_CANONICAL_URL());
expect(await niceDemoAppView.getPrincipal()).toBe("2vxsx-fae");
await niceDemoAppView.signin();

Expand Down
18 changes: 8 additions & 10 deletions src/frontend/src/test-e2e/constants.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
// Read canister ids from the corresponding dfx files.
// This assumes that they have been successfully dfx-deployed
import { readFileSync } from "fs";
export const test_app_canister_ids = JSON.parse(
readFileSync(".dfx/local/canister_ids.json", "utf-8")
);
import { readCanisterId } from "../../../../vite.plugins";

const TEST_APP_CANISTER_ID = test_app_canister_ids.test_app.local;
const testAppCanisterId = () => readCanisterId({ canisterName: "test_app" });

export const TEST_APP_CANONICAL_URL = `https://${TEST_APP_CANISTER_ID}.icp0.io`;
export const TEST_APP_CANONICAL_URL_RAW = `https://${TEST_APP_CANISTER_ID}.raw.icp0.io`;
export const TEST_APP_CANONICAL_URL_LEGACY = `https://${TEST_APP_CANISTER_ID}.ic0.app`;
export const TEST_APP_CANONICAL_URL = async () =>
`https://${await testAppCanisterId()}.icp0.io`;
export const TEST_APP_CANONICAL_URL_RAW = async () =>
`https://${await testAppCanisterId()}.raw.icp0.io`;
export const TEST_APP_CANONICAL_URL_LEGACY = async () =>
`https://${await testAppCanisterId()}.ic0.app`;
export const TEST_APP_NICE_URL = "https://nice-name.com";
export const II_URL =
process.env.II_URL ?? "https://identity.internetcomputer.org";
Expand Down
14 changes: 9 additions & 5 deletions src/frontend/src/test-e2e/principals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ test("Should issue the same principal to nice url and canonical url", async () =
expect(credentials).toHaveLength(1);

const canonicalDemoAppView = new DemoAppView(browser);
await canonicalDemoAppView.open(TEST_APP_CANONICAL_URL, II_URL);
await canonicalDemoAppView.open(await TEST_APP_CANONICAL_URL(), II_URL);
await canonicalDemoAppView.waitForDisplay();
await canonicalDemoAppView.setDerivationOrigin(TEST_APP_CANONICAL_URL);
await canonicalDemoAppView.setDerivationOrigin(
await TEST_APP_CANONICAL_URL()
);
expect(await canonicalDemoAppView.getPrincipal()).toBe("2vxsx-fae");
await canonicalDemoAppView.signin();

Expand All @@ -52,7 +54,7 @@ test("Should issue the same principal to nice url and canonical url", async () =
`{"alternativeOrigins":["${TEST_APP_NICE_URL}"]}`,
"certified"
);
await niceDemoAppView.setDerivationOrigin(TEST_APP_CANONICAL_URL);
await niceDemoAppView.setDerivationOrigin(await TEST_APP_CANONICAL_URL());
expect(await niceDemoAppView.getPrincipal()).toBe("2vxsx-fae");
await niceDemoAppView.signin();

Expand Down Expand Up @@ -107,8 +109,10 @@ test("Should issue the same principal to dapps on legacy & official domains", as
};

// Compare that principals issues for ic0.app & icp0.io are the same
const principal1 = await authenticate(TEST_APP_CANONICAL_URL);
const principal2 = await authenticate(TEST_APP_CANONICAL_URL_LEGACY);
const principal1 = await authenticate(await TEST_APP_CANONICAL_URL());
const principal2 = await authenticate(
await TEST_APP_CANONICAL_URL_LEGACY()
);

expect(principal1).toEqual(principal2);
});
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/test-e2e/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export async function addCustomCommands(
{
name: "authenticatorId",
type: "string",
description: "The id of the authenticator to remove",
description: "The id of the authenticator to TODO",
required: true,
},
],
Expand Down
31 changes: 5 additions & 26 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { nonNullish } from "@dfinity/utils";
import basicSsl from "@vitejs/plugin-basic-ssl";
import { existsSync } from "fs";
import { resolve } from "path";
import { AliasOptions, UserConfig, defineConfig } from "vite";
import {
compression,
injectCanisterIdPlugin,
minifyHTML,
readCanisterId,
replicaForwardPlugin,
} from "./vite.plugins";

Expand All @@ -30,13 +27,6 @@ export default defineConfig(({ mode }: UserConfig): UserConfig => {
II_VERSION: `${process.env.II_VERSION ?? ""}`,
};

const testAppCanisterId = existsSync(".dfx/local/canister_ids.json")
? readCanisterId({
canisterName: "test_app",
canisterIdsJsonFile: ".dfx/local/canister_ids.json",
})
: undefined;

// Path "../../" have to be expressed relative to the "root".
// e.g.
// root = src/frontend
Expand Down Expand Up @@ -75,26 +65,15 @@ export default defineConfig(({ mode }: UserConfig): UserConfig => {
replicaForwardPlugin({
replicaOrigin: "127.0.0.1:4943",
forwardRules: [
...(nonNullish(testAppCanisterId)
? [
{
hosts: [
"nice-name.com",
`${testAppCanisterId}.ic0.app`,
`${testAppCanisterId}.icp0.io`,
],
canisterId: testAppCanisterId,
},
]
: []),
{
hosts: ["nice-name.com"],
canisterName: "test_app",
},
...(process.env.NO_HOT_RELOAD === "1"
? [
{
hosts: ["identity.ic0.app", "identity.internetcomputer.org"],
canisterId: readCanisterId({
canisterName: "internet_identity",
canisterIdsJsonFile: ".dfx/local/canister_ids.json",
}),
canisterName: "internet_identity",
},
]
: []),
Expand Down
77 changes: 45 additions & 32 deletions vite.plugins.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,27 @@
import { assertNonNullish, isNullish } from "@dfinity/utils";
import { readFileSync } from "fs";
import { isNullish } from "@dfinity/utils";
import { exec } from "child_process";
import { minify } from "html-minifier-terser";
import httpProxy from "http-proxy";
import { extname } from "path";
import { promisify } from "util";
import { Plugin, ViteDevServer } from "vite";
import viteCompression from "vite-plugin-compression";

/**
* Read a canister ID from dfx's local state
*/
export const readCanisterId = ({
export const readCanisterId = async ({
canisterName,
canisterIdsJsonFile,
}: {
canisterName: string;
canisterIdsJsonFile: string;
}): string => {
}): Promise<string> => {
try {
const canisterIds: Record<string, { local: string }> = JSON.parse(
readFileSync(canisterIdsJsonFile, "utf-8")
);
const canisterId = canisterIds[canisterName]?.local;
assertNonNullish(
canisterId,
`Could not get canister ID from ${canisterIdsJsonFile}`
);
console.log(
`Read canister ID '${canisterId} for canister with name '${canisterName}'`
);

return canisterId;
const execP = await promisify(exec)(`dfx canister id ${canisterName}`);
const res = execP.stdout.trim();
console.log("Canister: ", canisterName, res);
return res;
} catch (e) {
throw Error(`Could not get canister ID from ${canisterIdsJsonFile}: ${e}`);
throw Error(`Could not get canister ID: ${e}`);
}
};

Expand All @@ -41,17 +31,17 @@ export const readCanisterId = ({
*/
export const injectCanisterIdPlugin = (): {
name: "html-transform";
transformIndexHtml(html: string): string;
transformIndexHtml(html: string): Promise<string>;
} => ({
name: "html-transform",
transformIndexHtml(html): string {
async transformIndexHtml(html): Promise<string> {
const rgx = /<script type="module" src="(?<src>[^"]+)"><\/script>/;
const canisterId = await readCanisterId({
canisterName: "internet_identity",
});

return html.replace(rgx, (_match, src) => {
return `<script data-canister-id="${readCanisterId({
canisterName: "internet_identity",
canisterIdsJsonFile: "./.dfx/local/canister_ids.json",
})}" type="module" src="${src}"></script>`;
return `<script data-canister-id="${canisterId}" type="module" src="${src}"></script>`;
});
},
});
Expand Down Expand Up @@ -95,15 +85,15 @@ export const replicaForwardPlugin = ({
forwardRules,
}: {
replicaOrigin: string;
forwardRules: Array<{ canisterId: string; hosts: string[] }>;
forwardRules: Array<{ canisterName: string; hosts: string[] }>;
}) => ({
name: "replica-forward",
configureServer(server: ViteDevServer) {
const proxy = httpProxy.createProxyServer({
secure: false,
});

server.middlewares.use((req, res, next) => {
server.middlewares.use(async (req, res, next) => {
if (
/* Deny requests to raw URLs, e.g. <canisterId>.raw.ic0.app to make sure that II always uses certified assets
* to verify the alternative origins. */
Expand All @@ -127,14 +117,37 @@ export const replicaForwardPlugin = ({
rule.hosts.includes(host)
);
if (isNullish(matchingRule)) {
// default handling
return next();
const domain = host.split(".")[0];
if (/([a-z0-9])+(-[a-z0-9]+)+/.test(domain)) {
const canisterId = domain;

console.log(
`forwarding ${req.method} https://${req.headers.host}${req.url} to canister ${canisterId}`
);
req.headers["host"] = `${canisterId}.localhost`;
proxy.web(req, res, {
target: `http://${replicaOrigin}`,
});

proxy.on("error", (err: Error) => {
res.statusCode = 500;
res.end("Replica forwarding failed: " + err.message);
});
return;
} else {
// default handling
return next();
}
}

const canisterId = await readCanisterId({
canisterName: matchingRule.canisterName,
});

console.log(
`forwarding ${req.method} https://${req.headers.host}${req.url} to canister ${matchingRule.canisterId}`
`forwarding ${req.method} https://${req.headers.host}${req.url} to canister ${canisterId}`
);
req.headers["host"] = `${matchingRule.canisterId}.localhost`;
req.headers["host"] = `${canisterId}.localhost`;
proxy.web(req, res, {
target: `http://${replicaOrigin}`,
});
Expand Down

0 comments on commit eefcfd1

Please sign in to comment.