Skip to content

Commit

Permalink
refactor: audit code
Browse files Browse the repository at this point in the history
  • Loading branch information
hung-cybo committed Apr 24, 2024
1 parent b45ea6a commit b358df3
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 172 deletions.
20 changes: 10 additions & 10 deletions packages/plugin-uploader/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import fs from "fs";

import { getBoundMessage } from "./messages";
import type { BasicAuth } from "./pluginSystemPage";
import { PluginSystemPage } from "./pluginSystemPage";
import type { BasicAuth } from "./pages/PluginSystemPage";
import { PluginSystemPage } from "./pages/PluginSystemPage";
import type { Lang } from "./lang";

export interface Option {
interface Option {
proxyServer?: string;
watch?: boolean;
lang: Lang;
Expand Down Expand Up @@ -38,8 +37,9 @@ export const run = async (
basicAuth,
};
try {
let page = await pluginSystemPage.readyForUpload(params);
await pluginSystemPage.upload(page, pluginPath, lang);
await pluginSystemPage.openNewPage(browser);
await pluginSystemPage.readyForUpload(params);
await pluginSystemPage.upload(pluginPath, lang);
if (options.watch) {
let uploading = false;
fs.watch(pluginPath, async () => {
Expand All @@ -48,21 +48,21 @@ export const run = async (
}
try {
uploading = true;
await pluginSystemPage.upload(page, pluginPath, lang);
await pluginSystemPage.upload(pluginPath, lang);
} catch (e) {
console.log(e);
console.log(boundMessage("Error_retry"));
await browser.close();
browser = await pluginSystemPage.launchBrowser(options.proxyServer);
page = await pluginSystemPage.readyForUpload({
browser,
await pluginSystemPage.openNewPage(browser);
await pluginSystemPage.readyForUpload({
baseUrl,
userName,
password,
lang,
basicAuth,
});
await pluginSystemPage.upload(page, pluginPath, lang);
await pluginSystemPage.upload(pluginPath, lang);
} finally {
uploading = false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import type { Page } from "puppeteer";
import type { BoundMessage } from "./messages";
import { getBoundMessage } from "./messages";
import type { BoundMessage } from "../messages";
import { getBoundMessage } from "../messages";
import chalk from "chalk";
import type { Lang } from "./lang";
import type { PageInterface } from "./PageInterface";
import type { Lang } from "../lang";
import type { PluginSystemPageBase } from "./PluginSystemPageBase";

const TIMEOUT_MS = 10000;
const UPLOAD_TIMEOUT_MS = 60000;

export const IMPORT_BUTTON_SELECTOR =
"#page-admin-system-plugin-index-addplugin";
const IMPORT_PLUGIN_DIALOG_SELECTOR = ".ocean-ui-dialog";
const FILE_SELECTOR = '.plupload > input[type="file"]';

export class OldPage implements PageInterface {
export class OldPluginSystemPage implements PluginSystemPageBase {
public async readyForImportButton(
page: Page,
boundMessage: BoundMessage,
Expand All @@ -33,9 +35,11 @@ export class OldPage implements PageInterface {
const boundMessage = getBoundMessage(lang);
console.log(`Trying to upload ${pluginPath}`);
await page.click(IMPORT_BUTTON_SELECTOR);

const file = await page.$('.plupload > input[type="file"]');
if (file == null) {
await page.waitForSelector(IMPORT_PLUGIN_DIALOG_SELECTOR, {
timeout: TIMEOUT_MS,
});
const file = await page.$(FILE_SELECTOR);
if (file === null) {
throw new Error('input[type="file"] is not found');
}
await file.uploadFile(pluginPath);
Expand Down
150 changes: 150 additions & 0 deletions packages/plugin-uploader/src/pages/PluginSystemPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import type { Browser, Page } from "puppeteer";
import puppeteer from "puppeteer";
import type { Lang } from "../lang";
import chalk from "chalk";
import type { BoundMessage } from "../messages";
import { getBoundMessage } from "../messages";
import { ReactPluginSystemPage } from "./ReactPluginSystemPage";
import type { PluginSystemPageBase } from "./PluginSystemPageBase";
import {
IMPORT_BUTTON_SELECTOR,
OldPluginSystemPage,
} from "./OldPluginSystemPage";

const TIMEOUT_MS = 10000;
const DETECT_PAGE_TIMEOUT_MS = 10000;
const NO_PRIVILEGE_STATUS_CODE = "403";

export interface BasicAuth {
username: string;
password: string;
}

export class PluginSystemPage {
private ui?: PluginSystemPageBase;
private _page?: Page;

public get page() {
if (this._page === undefined) {
throw new Error(
"Page is not opened yet. Please call openNewPage() first.",
);
}
return this._page;
}

public set page(value) {
this._page = value;
}

private async getUI() {
if (this.ui) {
return this.ui;
}

const isReactPage = await this.isReactPage();
this.ui = isReactPage
? new ReactPluginSystemPage()
: new OldPluginSystemPage();

return this.ui;
}

private async isReactPage(): Promise<boolean> {
try {
await this.page.waitForSelector(IMPORT_BUTTON_SELECTOR, {
timeout: DETECT_PAGE_TIMEOUT_MS,
});
return false;
} catch (e) {
return true;
}
}

public async openNewPage(browser: Browser) {
this._page = await browser.newPage();
}

protected async login(options: {
baseUrl: string;
userName: string;
password: string;
boundMessage: BoundMessage;
basicAuth?: BasicAuth;
}): Promise<void> {
const { baseUrl, userName, password, boundMessage, basicAuth } = options;
const loginUrl = `${baseUrl}/login?saml=off`;

if (basicAuth) {
await this.page.authenticate(basicAuth);
}

console.log(`Open ${loginUrl}`);
await this.page.goto(loginUrl);
try {
await this.page.waitForSelector(".form-username-slash", {
timeout: TIMEOUT_MS,
});
} catch (e) {
throw chalk.red(boundMessage("Error_cannotOpenLogin"));
}

console.log("Trying to log in...");
await this.page.type(".form-username-slash > input.form-text", userName);
await this.page.type(".form-password-slash > input.form-text", password);
await this.page.click(".login-button");

try {
await this.page.waitForNavigation({
timeout: TIMEOUT_MS,
waitUntil: "domcontentloaded",
});
} catch (e) {
throw chalk.red(boundMessage("Error_failedLogin"));
}
}

protected goToPluginSystemPage(baseUrl: string) {
const pluginSystemPageUri = `${baseUrl}/k/admin/system/plugin/`;
console.log(`Navigate to ${pluginSystemPageUri}`);
return this.page.goto(pluginSystemPageUri);
}

public launchBrowser(
proxy?: string,
ignoreDefaultArgs?: string[],
): Promise<Browser> {
const args = proxy ? [`--proxy-server=${proxy}`] : [];
return puppeteer.launch({ args, ignoreDefaultArgs, headless: "shell" });
}

public async readyForUpload(options: {
baseUrl: string;
userName: string;
password: string;
lang: Lang;
basicAuth?: BasicAuth;
}): Promise<void> {
const { baseUrl, userName, password, lang, basicAuth } = options;
const boundMessage = getBoundMessage(lang);

await this.login({
baseUrl,
userName,
password,
boundMessage,
basicAuth,
});

const response = await this.goToPluginSystemPage(baseUrl);
if (!response || response.headers().status === NO_PRIVILEGE_STATUS_CODE) {
throw chalk.red(boundMessage("Error_adminPrivilege"));
}

await (await this.getUI()).readyForImportButton(this.page, boundMessage);
}

public async upload(pluginPath: string, lang: Lang): Promise<void> {
await (await this.getUI()).upload(this.page, pluginPath, lang);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { BoundMessage } from "./messages";
import type { BoundMessage } from "../messages";
import type { Page } from "puppeteer";
import type { Lang } from "./lang";
import type { Lang } from "../lang";

export interface PageInterface {
export interface PluginSystemPageBase {
readyForImportButton(page: Page, m: BoundMessage): Promise<void>;
upload(page: Page, pluginPath: string, lang: Lang): Promise<void>;
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import type { Page } from "puppeteer";
import type { BoundMessage } from "./messages";
import { getBoundMessage } from "./messages";
import type { BoundMessage } from "../messages";
import { getBoundMessage } from "../messages";
import chalk from "chalk";
import type { Lang } from "./lang";
import type { PageInterface } from "./PageInterface";
import type { Lang } from "../lang";
import type { PluginSystemPageBase } from "./PluginSystemPageBase";

const TIMEOUT_MS = 10000;
const UPLOAD_TIMEOUT_MS = 60000;

const IMPORT_BUTTON_SELECTOR = "button[data-testid='PluginImportButton']";
const IMPORT_PLUGIN_DIALOG_SELECTOR =
"//div[@data-testid='ImportDialog']//div[contains(@class,'_dialogContent')]";
const FILE_SELECTOR = "label[data-testid='FileSelector'] > input[type='file']";
const IMPORT_DIALOG_SELECTOR = "div[data-testid='ImportDialog']";
const IMPORT_BUTTON_IN_DIALOG_SELECTOR =
"//div[@data-testid='ImportDialog']//div[contains(@class,'_footer')]//button[1]";

export class ReactPage implements PageInterface {
export class ReactPluginSystemPage implements PluginSystemPageBase {
public async readyForImportButton(
page: Page,
boundMessage: BoundMessage,
Expand All @@ -36,15 +37,16 @@ export class ReactPage implements PageInterface {
const boundMessage = getBoundMessage(lang);
console.log(`Trying to upload ${pluginPath}`);
await page.click(IMPORT_BUTTON_SELECTOR);

await page.waitForSelector(`xpath/${IMPORT_PLUGIN_DIALOG_SELECTOR}`, {
timeout: TIMEOUT_MS,
});
const file = await page.$(FILE_SELECTOR);
if (file == null) {
if (file === null) {
throw new Error('input[type="file"] is not found');
}
await file.uploadFile(pluginPath);

await file.uploadFile(pluginPath);
await page.click(`xpath/${IMPORT_BUTTON_IN_DIALOG_SELECTOR}`);

await page.waitForSelector(`xpath/${IMPORT_BUTTON_IN_DIALOG_SELECTOR}`, {
hidden: true,
timeout: UPLOAD_TIMEOUT_MS,
Expand Down
Loading

0 comments on commit b358df3

Please sign in to comment.