From 48d54f3a647d17dd9d49936dae922f7f8243c14f Mon Sep 17 00:00:00 2001 From: Darran Boyd Date: Fri, 19 Jan 2024 13:27:09 +1100 Subject: [PATCH] feat(Browser extension): Initial iteration for Chrome (#71) * feat(Browser extension): Initial iteration for Chrome * Updated .gitignore * chore(Browser extension): Remove redundant API property assignment * chore(Browser extension): Removing /run directory --------- Co-authored-by: Darran Boyd --- .gitignore | 2 + .projenrc.ts | 67 +- package.json | 4 + .../.eslintrc.json | 237 +++ .../.gitattributes | 5 + .../.gitignore | 43 + .../.npmignore | 19 + .../.projen/deps.json | 104 ++ .../.projen/files.json | 16 + .../.projen/tasks.json | 247 +++ .../.wxt/tsconfig.json | 28 + .../.wxt/types/globals.d.ts | 13 + .../.wxt/types/i18n.d.ts | 78 + .../.wxt/types/imports.d.ts | 17 + .../.wxt/types/paths.d.ts | 16 + .../.wxt/wxt.d.ts | 6 + .../LICENSE | 202 ++ .../README.md | 1 + .../package.json | 96 + .../project.json | 136 ++ .../src/debugLogger.ts | 21 + .../src/entrypoints/background.ts | 60 + .../src/entrypoints/content-script.ts | 261 +++ .../src/entrypoints/popup/App.tsx | 37 + .../src/entrypoints/popup/ConfigView.tsx | 217 +++ .../src/entrypoints/popup/config.ts | 74 + .../src/entrypoints/popup/index.html | 13 + .../src/entrypoints/popup/main.tsx | 26 + .../src/public/scriptInjectForCodeCatalyst.js | 41 + .../public/scriptInjectForThreatComposer.js | 78 + .../tsconfig.dev.json | 40 + .../tsconfig.json | 38 + .../wxt.config.ts | 51 + .../generic/WindowExporter/index.tsx | 4 - yarn.lock | 1634 ++++++++++++++++- 35 files changed, 3882 insertions(+), 50 deletions(-) create mode 100644 packages/threat-composer-app-browser-extension/.eslintrc.json create mode 100644 packages/threat-composer-app-browser-extension/.gitattributes create mode 100644 packages/threat-composer-app-browser-extension/.gitignore create mode 100644 packages/threat-composer-app-browser-extension/.npmignore create mode 100644 packages/threat-composer-app-browser-extension/.projen/deps.json create mode 100644 packages/threat-composer-app-browser-extension/.projen/files.json create mode 100644 packages/threat-composer-app-browser-extension/.projen/tasks.json create mode 100644 packages/threat-composer-app-browser-extension/.wxt/tsconfig.json create mode 100644 packages/threat-composer-app-browser-extension/.wxt/types/globals.d.ts create mode 100644 packages/threat-composer-app-browser-extension/.wxt/types/i18n.d.ts create mode 100644 packages/threat-composer-app-browser-extension/.wxt/types/imports.d.ts create mode 100644 packages/threat-composer-app-browser-extension/.wxt/types/paths.d.ts create mode 100644 packages/threat-composer-app-browser-extension/.wxt/wxt.d.ts create mode 100644 packages/threat-composer-app-browser-extension/LICENSE create mode 100644 packages/threat-composer-app-browser-extension/README.md create mode 100644 packages/threat-composer-app-browser-extension/package.json create mode 100644 packages/threat-composer-app-browser-extension/project.json create mode 100644 packages/threat-composer-app-browser-extension/src/debugLogger.ts create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/background.ts create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/content-script.ts create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/popup/App.tsx create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/popup/ConfigView.tsx create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/popup/config.ts create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/popup/index.html create mode 100644 packages/threat-composer-app-browser-extension/src/entrypoints/popup/main.tsx create mode 100644 packages/threat-composer-app-browser-extension/src/public/scriptInjectForCodeCatalyst.js create mode 100644 packages/threat-composer-app-browser-extension/src/public/scriptInjectForThreatComposer.js create mode 100644 packages/threat-composer-app-browser-extension/tsconfig.dev.json create mode 100644 packages/threat-composer-app-browser-extension/tsconfig.json create mode 100644 packages/threat-composer-app-browser-extension/wxt.config.ts diff --git a/.gitignore b/.gitignore index 45ccbe2e..d3475d5e 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ jspm_packages/ .temp/ oss-attribution/ storybook.out/ +.DS_Store +.output/ diff --git a/.projenrc.ts b/.projenrc.ts index de9a4aa6..c0539bea 100644 --- a/.projenrc.ts +++ b/.projenrc.ts @@ -9,7 +9,7 @@ const monorepo = new NxMonorepoProject({ defaultReleaseBranch: "main", name: "@aws/threat-composer-monorepo", devDeps: [ - "@aws-prototyping-sdk/nx-monorepo@^0.19.2", + "@aws-prototyping-sdk/nx-monorepo@^0.19.2", "@aws-prototyping-sdk/pipeline@^0.19.2", "@aws-prototyping-sdk/pdk-nag@^0.19.2", "eslint-plugin-header", @@ -26,9 +26,14 @@ monorepo.tryFindObjectFile("package.json")?.addOverride("resolutions.js-yaml", " monorepo.tryFindObjectFile("package.json")?.addOverride("resolutions.semver", "^7.5.3"); monorepo.tryFindObjectFile("package.json")?.addOverride("resolutions.@babel/traverse", "^7.23.2"); monorepo.tryFindObjectFile("package.json")?.addOverride("resolutions.postcss", "^8.4.31"); +monorepo + .tryFindObjectFile("package.json") + ?.addOverride("workspaces.nohoist", ["**/wxt"]); monorepo.addGitIgnore('.temp/'); monorepo.addGitIgnore('oss-attribution/'); monorepo.addGitIgnore('storybook.out/'); +monorepo.addGitIgnore(".DS_Store"); +monorepo.addGitIgnore(".output/"); monorepo.addTask('export:examples', { steps: [ @@ -68,7 +73,7 @@ monorepo.addTask('storybook', { monorepo.compileTask.reset('npx nx run-many --target=build --all --skip-nx-cache --nx-bail'); monorepo.postCompileTask.reset('yarn run generate:attribution && yarn run license:checker'); -const uiESModules = [ +const uiESModules = [ "unified", "@aws-northstar/ui" ].join("|"); @@ -143,7 +148,7 @@ const uiProject = new TypeScriptProject({ transformIgnorePatterns: [ `[/\\\\]node_modules[/\\\\](?!${uiESModules}).+\\.(js|jsx|mjs|cjs|ts|tsx)$`, ], - }, + }, }, tsconfig: { compilerOptions: { @@ -253,7 +258,63 @@ infraProject.eslint?.addRules({ "header/header": [2, "../../header.js"], }); +const browserExtensionProject = new TypeScriptProject({ + parent: monorepo, + outdir: "packages/threat-composer-app-browser-extension", + defaultReleaseBranch: "main", + name: "@aws/threat-composer-app-browser-extension", + deps: [ + "react-router-dom", + "@cloudscape-design/components", + "react", + "react-dom", + ], + devDeps: [ + "wxt@^0.14.0", + "@vitejs/plugin-react", + "rollup-plugin-copy", + "@types/react", + "@types/react-dom", + ], + sampleCode: false, + tsconfig: { + compilerOptions: { + lib: ["dom", "dom.iterable"], + jsx: TypeScriptJsxMode.REACT_JSX, + }, + include: ["src", ".wxt/types"], + }, +}); + +browserExtensionProject.addTask("dev", { + exec: "wxt", +}); + +browserExtensionProject.addTask("dev:firefox", { + exec: "wxt --browser firefox", +}); + +browserExtensionProject.compileTask.reset("wxt build"); + +browserExtensionProject.addTask("zip", { + exec: "wxt zip", +}); + +browserExtensionProject.addTask("zip:firefox", { + exec: "wxt zip --browser firefox", +}); + +browserExtensionProject.addTask("postinstall", { + exec: "wxt prepare", +}); + +browserExtensionProject.eslint?.addPlugins("header"); +browserExtensionProject.eslint?.addRules({ + "header/header": [2, "../../header.js"], +}); + monorepo.addImplicitDependency(appProject, uiProject); monorepo.addImplicitDependency(infraProject, appProject); +monorepo.addImplicitDependency(browserExtensionProject, appProject); monorepo.synth(); diff --git a/package.json b/package.json index 7756ad38..44172b91 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,11 @@ "packages": [ "packages/threat-composer", "packages/threat-composer-app", + "packages/threat-composer-app-browser-extension", "packages/threat-composer-infra" + ], + "nohoist": [ + "**/wxt" ] }, "resolutions": { diff --git a/packages/threat-composer-app-browser-extension/.eslintrc.json b/packages/threat-composer-app-browser-extension/.eslintrc.json new file mode 100644 index 00000000..2093e289 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.eslintrc.json @@ -0,0 +1,237 @@ +// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +{ + "env": { + "jest": true, + "node": true + }, + "root": true, + "plugins": [ + "@typescript-eslint", + "import", + "header" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "project": "./tsconfig.dev.json" + }, + "extends": [ + "plugin:import/typescript" + ], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [ + ".ts", + ".tsx" + ] + }, + "import/resolver": { + "node": {}, + "typescript": { + "project": "./tsconfig.dev.json", + "alwaysTryTypes": true + } + } + }, + "ignorePatterns": [ + "*.js", + "!.projenrc.js", + "*.d.ts", + "node_modules/", + "*.generated.ts", + "coverage" + ], + "rules": { + "indent": [ + "off" + ], + "@typescript-eslint/indent": [ + "error", + 2 + ], + "quotes": [ + "error", + "single", + { + "avoidEscape": true + } + ], + "comma-dangle": [ + "error", + "always-multiline" + ], + "comma-spacing": [ + "error", + { + "before": false, + "after": true + } + ], + "no-multi-spaces": [ + "error", + { + "ignoreEOLComments": false + } + ], + "array-bracket-spacing": [ + "error", + "never" + ], + "array-bracket-newline": [ + "error", + "consistent" + ], + "object-curly-spacing": [ + "error", + "always" + ], + "object-curly-newline": [ + "error", + { + "multiline": true, + "consistent": true + } + ], + "object-property-newline": [ + "error", + { + "allowAllPropertiesOnSameLine": true + } + ], + "keyword-spacing": [ + "error" + ], + "brace-style": [ + "error", + "1tbs", + { + "allowSingleLine": true + } + ], + "space-before-blocks": [ + "error" + ], + "curly": [ + "error", + "multi-line", + "consistent" + ], + "@typescript-eslint/member-delimiter-style": [ + "error" + ], + "semi": [ + "error", + "always" + ], + "max-len": [ + "error", + { + "code": 150, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true, + "ignoreComments": true, + "ignoreRegExpLiterals": true + } + ], + "quote-props": [ + "error", + "consistent-as-needed" + ], + "@typescript-eslint/no-require-imports": [ + "error" + ], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": [ + "**/test/**", + "**/build-tools/**" + ], + "optionalDependencies": false, + "peerDependencies": true + } + ], + "import/no-unresolved": [ + "error" + ], + "import/order": [ + "warn", + { + "groups": [ + "builtin", + "external" + ], + "alphabetize": { + "order": "asc", + "caseInsensitive": true + } + } + ], + "no-duplicate-imports": [ + "error" + ], + "no-shadow": [ + "off" + ], + "@typescript-eslint/no-shadow": [ + "error" + ], + "key-spacing": [ + "error" + ], + "no-multiple-empty-lines": [ + "error" + ], + "@typescript-eslint/no-floating-promises": [ + "error" + ], + "no-return-await": [ + "off" + ], + "@typescript-eslint/return-await": [ + "error" + ], + "no-trailing-spaces": [ + "error" + ], + "dot-notation": [ + "error" + ], + "no-bitwise": [ + "error" + ], + "@typescript-eslint/member-ordering": [ + "error", + { + "default": [ + "public-static-field", + "public-static-method", + "protected-static-field", + "protected-static-method", + "private-static-field", + "private-static-method", + "field", + "constructor", + "method" + ] + } + ], + "header/header": [ + 2, + "../../header.js" + ] + }, + "overrides": [ + { + "files": [ + ".projenrc.js" + ], + "rules": { + "@typescript-eslint/no-require-imports": "off", + "import/no-extraneous-dependencies": "off" + } + } + ] +} diff --git a/packages/threat-composer-app-browser-extension/.gitattributes b/packages/threat-composer-app-browser-extension/.gitattributes new file mode 100644 index 00000000..608613ae --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.gitattributes @@ -0,0 +1,5 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". + +/.gitattributes linguist-generated +/.projen/** linguist-generated +/yarn.lock linguist-generated \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/.gitignore b/packages/threat-composer-app-browser-extension/.gitignore new file mode 100644 index 00000000..30feee4e --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.gitignore @@ -0,0 +1,43 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +!/.gitattributes +!/.projen/tasks.json +!/.projen/deps.json +!/.projen/files.json +!/package.json +!/LICENSE +!/.npmignore +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json +pids +*.pid +*.seed +*.pid.lock +lib-cov +coverage +*.lcov +.nyc_output +build/Release +node_modules/ +jspm_packages/ +*.tsbuildinfo +.eslintcache +*.tgz +.yarn-integrity +.cache +!/.projenrc.js +/test-reports/ +junit.xml +/coverage/ +!/test/ +!/tsconfig.json +!/tsconfig.dev.json +!/src/ +/lib +/dist/ +!/.eslintrc.json +!/project.json diff --git a/packages/threat-composer-app-browser-extension/.npmignore b/packages/threat-composer-app-browser-extension/.npmignore new file mode 100644 index 00000000..a38b392a --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.npmignore @@ -0,0 +1,19 @@ +# ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +/.projen/ +/test-reports/ +junit.xml +/coverage/ +/test/ +/tsconfig.dev.json +/src/ +!/lib/ +!/lib/**/*.js +!/lib/**/*.d.ts +dist +/tsconfig.json +/.github/ +/.vscode/ +/.idea/ +/.projenrc.js +tsconfig.tsbuildinfo +/.eslintrc.json diff --git a/packages/threat-composer-app-browser-extension/.projen/deps.json b/packages/threat-composer-app-browser-extension/.projen/deps.json new file mode 100644 index 00000000..71a5a931 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.projen/deps.json @@ -0,0 +1,104 @@ +{ + "dependencies": [ + { + "name": "@types/jest", + "type": "build" + }, + { + "name": "@types/node", + "version": "^14", + "type": "build" + }, + { + "name": "@types/react", + "type": "build" + }, + { + "name": "@types/react-dom", + "type": "build" + }, + { + "name": "@typescript-eslint/eslint-plugin", + "version": "^5", + "type": "build" + }, + { + "name": "@typescript-eslint/parser", + "version": "^5", + "type": "build" + }, + { + "name": "@vitejs/plugin-react", + "type": "build" + }, + { + "name": "eslint-import-resolver-node", + "type": "build" + }, + { + "name": "eslint-import-resolver-typescript", + "type": "build" + }, + { + "name": "eslint-plugin-import", + "type": "build" + }, + { + "name": "eslint", + "version": "^8", + "type": "build" + }, + { + "name": "jest", + "type": "build" + }, + { + "name": "jest-junit", + "version": "^13", + "type": "build" + }, + { + "name": "npm-check-updates", + "version": "^16", + "type": "build" + }, + { + "name": "projen", + "type": "build" + }, + { + "name": "rollup-plugin-copy", + "type": "build" + }, + { + "name": "ts-jest", + "type": "build" + }, + { + "name": "typescript", + "type": "build" + }, + { + "name": "wxt", + "version": "^0.14.0", + "type": "build" + }, + { + "name": "@cloudscape-design/components", + "type": "runtime" + }, + { + "name": "react", + "type": "runtime" + }, + { + "name": "react-dom", + "type": "runtime" + }, + { + "name": "react-router-dom", + "type": "runtime" + } + ], + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/threat-composer-app-browser-extension/.projen/files.json b/packages/threat-composer-app-browser-extension/.projen/files.json new file mode 100644 index 00000000..1d6db55a --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.projen/files.json @@ -0,0 +1,16 @@ +{ + "files": [ + ".eslintrc.json", + ".gitattributes", + ".gitignore", + ".npmignore", + ".projen/deps.json", + ".projen/files.json", + ".projen/tasks.json", + "LICENSE", + "project.json", + "tsconfig.dev.json", + "tsconfig.json" + ], + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/threat-composer-app-browser-extension/.projen/tasks.json b/packages/threat-composer-app-browser-extension/.projen/tasks.json new file mode 100644 index 00000000..ad51f577 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.projen/tasks.json @@ -0,0 +1,247 @@ +{ + "tasks": { + "build": { + "name": "build", + "description": "Full release build", + "steps": [ + { + "spawn": "pre-compile" + }, + { + "spawn": "compile" + }, + { + "spawn": "post-compile" + }, + { + "spawn": "test" + }, + { + "spawn": "package" + } + ] + }, + "clobber": { + "name": "clobber", + "description": "hard resets to HEAD of origin and cleans the local repo", + "env": { + "BRANCH": "$(git branch --show-current)" + }, + "steps": [ + { + "exec": "git checkout -b scratch", + "name": "save current HEAD in \"scratch\" branch" + }, + { + "exec": "git checkout $BRANCH" + }, + { + "exec": "git fetch origin", + "name": "fetch latest changes from origin" + }, + { + "exec": "git reset --hard origin/$BRANCH", + "name": "hard reset to origin commit" + }, + { + "exec": "git clean -fdx", + "name": "clean all untracked files" + }, + { + "say": "ready to rock! (unpushed commits are under the \"scratch\" branch)" + } + ], + "condition": "git diff --exit-code > /dev/null" + }, + "compile": { + "name": "compile", + "description": "Only compile", + "steps": [ + { + "exec": "wxt build" + } + ] + }, + "default": { + "name": "default", + "description": "Synthesize project files" + }, + "dev": { + "name": "dev", + "steps": [ + { + "exec": "wxt" + } + ] + }, + "dev:firefox": { + "name": "dev:firefox", + "steps": [ + { + "exec": "wxt --browser firefox" + } + ] + }, + "eject": { + "name": "eject", + "description": "Remove projen from the project", + "env": { + "PROJEN_EJECTING": "true" + }, + "steps": [ + { + "spawn": "default" + } + ] + }, + "eslint": { + "name": "eslint", + "description": "Runs eslint against the codebase", + "steps": [ + { + "exec": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern src test build-tools .projenrc.js" + } + ] + }, + "install": { + "name": "install", + "description": "Install project dependencies and update lockfile (non-frozen)", + "steps": [ + { + "exec": "yarn install --check-files" + } + ] + }, + "install:ci": { + "name": "install:ci", + "description": "Install project dependencies using frozen lockfile", + "steps": [ + { + "exec": "yarn install --check-files --frozen-lockfile" + } + ] + }, + "package": { + "name": "package", + "description": "Creates the distribution package", + "steps": [ + { + "exec": "mkdir -p dist/js" + }, + { + "exec": "mv $(npm pack) dist/js/" + } + ] + }, + "post-compile": { + "name": "post-compile", + "description": "Runs after successful compilation" + }, + "post-upgrade": { + "name": "post-upgrade", + "description": "Runs after upgrading dependencies" + }, + "postinstall": { + "name": "postinstall", + "steps": [ + { + "exec": "wxt prepare" + } + ] + }, + "pre-compile": { + "name": "pre-compile", + "description": "Prepare the project for compilation" + }, + "test": { + "name": "test", + "description": "Run tests", + "steps": [ + { + "exec": "jest --passWithNoTests --updateSnapshot", + "receiveArgs": true + }, + { + "spawn": "eslint" + } + ] + }, + "test:watch": { + "name": "test:watch", + "description": "Run jest in watch mode", + "steps": [ + { + "exec": "jest --watch" + } + ] + }, + "upgrade": { + "name": "upgrade", + "description": "upgrade dependencies", + "env": { + "CI": "0" + }, + "steps": [ + { + "exec": "yarn upgrade npm-check-updates" + }, + { + "exec": "npm-check-updates --dep dev --upgrade --target=minor" + }, + { + "exec": "npm-check-updates --dep optional --upgrade --target=minor" + }, + { + "exec": "npm-check-updates --dep peer --upgrade --target=minor" + }, + { + "exec": "npm-check-updates --dep prod --upgrade --target=minor" + }, + { + "exec": "npm-check-updates --dep bundle --upgrade --target=minor" + }, + { + "exec": "yarn install --check-files" + }, + { + "exec": "yarn upgrade" + }, + { + "exec": "npx projen" + }, + { + "spawn": "post-upgrade" + } + ] + }, + "watch": { + "name": "watch", + "description": "Watch & compile in the background", + "steps": [ + { + "exec": "tsc --build -w" + } + ] + }, + "zip": { + "name": "zip", + "steps": [ + { + "exec": "wxt zip" + } + ] + }, + "zip:firefox": { + "name": "zip:firefox", + "steps": [ + { + "exec": "wxt zip --browser firefox" + } + ] + } + }, + "env": { + "PATH": "$(npx -c \"node -e \\\"console.log(process.env.PATH)\\\"\")" + }, + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/threat-composer-app-browser-extension/.wxt/tsconfig.json b/packages/threat-composer-app-browser-extension/.wxt/tsconfig.json new file mode 100644 index 00000000..6f2e6804 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.wxt/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "@": ["../src"], + "@/*": ["../src/*"], + "~": ["../src"], + "~/*": ["../src/*"], + "@@": [".."], + "@@/*": ["../*"], + "~~": [".."], + "~~/*": ["../*"] + } + }, + "include": [ + "../**/*", + "./wxt.d.ts" + ], + "exclude": ["../.output"] +} \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/.wxt/types/globals.d.ts b/packages/threat-composer-app-browser-extension/.wxt/types/globals.d.ts new file mode 100644 index 00000000..40289d1b --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.wxt/types/globals.d.ts @@ -0,0 +1,13 @@ +// Generated by wxt +export {} +declare global { + const __MANIFEST_VERSION__: 2 | 3; + const __BROWSER__: string; + const __IS_CHROME__: boolean; + const __IS_FIREFOX__: boolean; + const __IS_SAFARI__: boolean; + const __IS_EDGE__: boolean; + const __IS_OPERA__: boolean; + const __COMMAND__: "build" | "serve"; + const __ENTRYPOINT__: string; +} diff --git a/packages/threat-composer-app-browser-extension/.wxt/types/i18n.d.ts b/packages/threat-composer-app-browser-extension/.wxt/types/i18n.d.ts new file mode 100644 index 00000000..bee3d0a9 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.wxt/types/i18n.d.ts @@ -0,0 +1,78 @@ +// Generated by wxt +import "wxt/browser"; + +declare module "wxt/browser" { + /** + * See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage + */ + interface GetMessageOptions { + /** + * See https://developer.chrome.com/docs/extensions/reference/i18n/#method-getMessage + */ + escapeLt?: boolean + } + + export interface WxtI18n extends I18n.Static { + /** + * The extension or app ID; you might use this string to construct URLs for resources inside the extension. Even unlocalized extensions can use this message. +Note: You can't use this message in a manifest file. + * + * "" + */ + getMessage( + messageName: "@@extension_id", + substitutions?: string | string[], + options?: GetMessageOptions, + ): string; + /** + * + * + * "" + */ + getMessage( + messageName: "@@ui_locale", + substitutions?: string | string[], + options?: GetMessageOptions, + ): string; + /** + * The text direction for the current locale, either "ltr" for left-to-right languages such as English or "rtl" for right-to-left languages such as Japanese. + * + * "" + */ + getMessage( + messageName: "@@bidi_dir", + substitutions?: string | string[], + options?: GetMessageOptions, + ): string; + /** + * If the @@bidi_dir is "ltr", then this is "rtl"; otherwise, it's "ltr". + * + * "" + */ + getMessage( + messageName: "@@bidi_reversed_dir", + substitutions?: string | string[], + options?: GetMessageOptions, + ): string; + /** + * If the @@bidi_dir is "ltr", then this is "left"; otherwise, it's "right". + * + * "" + */ + getMessage( + messageName: "@@bidi_start_edge", + substitutions?: string | string[], + options?: GetMessageOptions, + ): string; + /** + * If the @@bidi_dir is "ltr", then this is "right"; otherwise, it's "left". + * + * "" + */ + getMessage( + messageName: "@@bidi_end_edge", + substitutions?: string | string[], + options?: GetMessageOptions, + ): string; + } +} diff --git a/packages/threat-composer-app-browser-extension/.wxt/types/imports.d.ts b/packages/threat-composer-app-browser-extension/.wxt/types/imports.d.ts new file mode 100644 index 00000000..3b407f02 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.wxt/types/imports.d.ts @@ -0,0 +1,17 @@ +// Generated by wxt +export {} +declare global { + const ContentScriptContext: typeof import('wxt/client')['ContentScriptContext'] + const InvalidMatchPattern: typeof import('wxt/sandbox')['InvalidMatchPattern'] + const MatchPattern: typeof import('wxt/sandbox')['MatchPattern'] + const browser: typeof import('wxt/browser')['browser'] + const createIframeUi: typeof import('wxt/client')['createIframeUi'] + const createIntegratedUi: typeof import('wxt/client')['createIntegratedUi'] + const createShadowRootUi: typeof import('wxt/client')['createShadowRootUi'] + const defineBackground: typeof import('wxt/sandbox')['defineBackground'] + const defineConfig: typeof import('wxt')['defineConfig'] + const defineContentScript: typeof import('wxt/sandbox')['defineContentScript'] + const defineUnlistedScript: typeof import('wxt/sandbox')['defineUnlistedScript'] + const fakeBrowser: typeof import('wxt/testing')['fakeBrowser'] + const storage: typeof import('wxt/storage')['storage'] +} diff --git a/packages/threat-composer-app-browser-extension/.wxt/types/paths.d.ts b/packages/threat-composer-app-browser-extension/.wxt/types/paths.d.ts new file mode 100644 index 00000000..2dbdbd73 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.wxt/types/paths.d.ts @@ -0,0 +1,16 @@ +// Generated by wxt +import "wxt/browser"; + +declare module "wxt/browser" { + export type PublicPath = + | "/background.js" + | "/content-script.js" + | "/popup.html" + | "/scriptInjectForCodeCatalyst.js" + | "/scriptInjectForThreatComposer.js" + type HtmlPublicPath = Extract + export interface WxtRuntime extends Runtime.Static { + getURL(path: PublicPath): string; + getURL(path: `${HtmlPublicPath}${string}`): string; + } +} diff --git a/packages/threat-composer-app-browser-extension/.wxt/wxt.d.ts b/packages/threat-composer-app-browser-extension/.wxt/wxt.d.ts new file mode 100644 index 00000000..cc81f4c0 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/.wxt/wxt.d.ts @@ -0,0 +1,6 @@ +// Generated by wxt +/// +/// +/// +/// +/// diff --git a/packages/threat-composer-app-browser-extension/LICENSE b/packages/threat-composer-app-browser-extension/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/threat-composer-app-browser-extension/README.md b/packages/threat-composer-app-browser-extension/README.md new file mode 100644 index 00000000..b3fa7ddc --- /dev/null +++ b/packages/threat-composer-app-browser-extension/README.md @@ -0,0 +1 @@ +# replace this \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/package.json b/packages/threat-composer-app-browser-extension/package.json new file mode 100644 index 00000000..4b774f06 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/package.json @@ -0,0 +1,96 @@ +{ + "name": "@aws/threat-composer-app-browser-extension", + "scripts": { + "build": "npx projen build", + "clobber": "npx projen clobber", + "compile": "npx projen compile", + "default": "npx projen default", + "dev": "npx projen dev", + "dev:firefox": "npx projen dev:firefox", + "eject": "npx projen eject", + "eslint": "npx projen eslint", + "package": "npx projen package", + "post-compile": "npx projen post-compile", + "post-upgrade": "npx projen post-upgrade", + "postinstall": "npx projen postinstall", + "pre-compile": "npx projen pre-compile", + "test": "npx projen test", + "test:watch": "npx projen test:watch", + "upgrade": "npx projen upgrade", + "watch": "npx projen watch", + "zip": "npx projen zip", + "zip:firefox": "npx projen zip:firefox" + }, + "devDependencies": { + "@types/jest": "*", + "@types/node": "^14", + "@types/react": "*", + "@types/react-dom": "*", + "@typescript-eslint/eslint-plugin": "^5", + "@typescript-eslint/parser": "^5", + "@vitejs/plugin-react": "*", + "eslint": "^8", + "eslint-import-resolver-node": "*", + "eslint-import-resolver-typescript": "*", + "eslint-plugin-import": "*", + "jest": "*", + "jest-junit": "^13", + "npm-check-updates": "^16", + "projen": "*", + "rollup-plugin-copy": "*", + "ts-jest": "*", + "typescript": "*", + "wxt": "^0.14.0" + }, + "dependencies": { + "@cloudscape-design/components": "*", + "react": "*", + "react-dom": "*", + "react-router-dom": "*" + }, + "main": "lib/index.js", + "license": "Apache-2.0", + "version": "0.0.0", + "jest": { + "testMatch": [ + "/src/**/__tests__/**/*.ts?(x)", + "/(test|src)/**/*(*.)@(spec|test).ts?(x)" + ], + "clearMocks": true, + "collectCoverage": true, + "coverageReporters": [ + "json", + "lcov", + "clover", + "cobertura", + "text" + ], + "coverageDirectory": "coverage", + "coveragePathIgnorePatterns": [ + "/node_modules/" + ], + "testPathIgnorePatterns": [ + "/node_modules/" + ], + "watchPathIgnorePatterns": [ + "/node_modules/" + ], + "reporters": [ + "default", + [ + "jest-junit", + { + "outputDirectory": "test-reports" + } + ] + ], + "preset": "ts-jest", + "globals": { + "ts-jest": { + "tsconfig": "tsconfig.dev.json" + } + } + }, + "types": "lib/index.d.ts", + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/threat-composer-app-browser-extension/project.json b/packages/threat-composer-app-browser-extension/project.json new file mode 100644 index 00000000..892770c8 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/project.json @@ -0,0 +1,136 @@ +{ + "name": "@aws/threat-composer-app-browser-extension", + "root": "packages/threat-composer-app-browser-extension", + "targets": { + "default": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen default", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "eject": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen eject", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "pre-compile": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen pre-compile", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "compile": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen compile", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "post-compile": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen post-compile", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "test": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen test", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "package": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen package", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "build": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen build", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "clobber": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen clobber", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "test:watch": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen test:watch", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "post-upgrade": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen post-upgrade", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "upgrade": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen upgrade", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "watch": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen watch", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "eslint": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen eslint", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "dev": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen dev", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "dev:firefox": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen dev:firefox", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "zip": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen zip", + "cwd": "packages/threat-composer-app-browser-extension" + } + }, + "zip:firefox": { + "executor": "nx:run-commands", + "options": { + "command": "yarn projen zip:firefox", + "cwd": "packages/threat-composer-app-browser-extension" + } + } + }, + "implicitDependencies": [ + "@aws/threat-composer-app" + ], + "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\"." +} diff --git a/packages/threat-composer-app-browser-extension/src/debugLogger.ts b/packages/threat-composer-app-browser-extension/src/debugLogger.ts new file mode 100644 index 00000000..7e8bc6ba --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/debugLogger.ts @@ -0,0 +1,21 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ +import { TCConfig } from './entrypoints/popup/config'; + +export function logDebugMessage(config: TCConfig, msg: string) { + const debugPrefix = 'ThreatComposerExtension: '; + if (config.debug) console.log(debugPrefix + msg); +}; \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/background.ts b/packages/threat-composer-app-browser-extension/src/entrypoints/background.ts new file mode 100644 index 00000000..2ee2125a --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/background.ts @@ -0,0 +1,60 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ + +import { getExtensionConfig, ThreatComposerTarget } from './popup/config'; +import { logDebugMessage } from '../debugLogger'; + +export default defineBackground(() => { + getExtensionConfig().then(config => { + logDebugMessage(config, 'index.hml is here:' + browser.runtime.getURL('index.html')); + + browser.runtime.onMessage.addListener(function (request: any) { + const tcViewer = config.target; + let tcUrlCreate = ''; + let tcUrlUpdate = ''; + + if (tcViewer == ThreatComposerTarget.BUILT_IN) { + tcUrlCreate = browser.runtime.getURL('index.html'); + tcUrlUpdate = browser.runtime.getURL('*'); + } else if (tcViewer == ThreatComposerTarget.GITHUB_PAGES) { + tcUrlCreate = 'https://awslabs.github.io/threat-composer'; + tcUrlUpdate = tcUrlCreate; + } else if (tcViewer == ThreatComposerTarget.CUSTOM_HOST) { + tcUrlCreate = config.customUrl ?? ''; + tcUrlUpdate = tcUrlCreate; + } + + if (request.schema) { + //This is likely the JSON from a threat model + logDebugMessage(config, 'Message recieved - Threat Model JSON'); + + browser.storage.local.set({ threatModel: request }).then(() => { + logDebugMessage(config, 'Saved to browser storage'); + }); + + browser.tabs.query({ url: tcUrlUpdate }).then((tabs: any) => { + if (tabs.length > 0) { + browser.tabs.update(tabs[0].id, { active: true }); + } else { + browser.tabs.create({ url: tcUrlCreate }); + } + }); + } + }); + }).catch((error) => { + logDebugMessage({ debug: true } as any, error); + }); +}); \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/content-script.ts b/packages/threat-composer-app-browser-extension/src/entrypoints/content-script.ts new file mode 100644 index 00000000..4a95e9b9 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/content-script.ts @@ -0,0 +1,261 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ + +import { getExtensionConfig, TCConfig } from './popup/config'; +import { logDebugMessage } from '../debugLogger'; +interface TCJSONSimplifiedSchema { + schema?: string; +} + +interface TCGitHubState { + previousUrl: string; + stopProcessing: boolean; +} + +interface TCCodeCatalystState { + stopProcessing: boolean; +} + +interface TCCodeBrowserState { + stopProcessing: boolean; +} + + +function isLikelyThreatComposerSchema(JSONobj: TCJSONSimplifiedSchema) { + return JSONobj.schema ? true : false; +}; + +async function getTCJSONCandidate(url: string, element: HTMLElement, config: TCConfig) { + const tcJSONCandidate: TCJSONSimplifiedSchema = await fetch(url) + .then(function (response) { + logDebugMessage(config, 'Able to get a JSON candidate'); + return response.json(); + }) + .catch(function (error) { + logDebugMessage(config, 'Error during fetch: ' + error.message); + }); + + if (tcJSONCandidate && isLikelyThreatComposerSchema(tcJSONCandidate)) { + logDebugMessage(config, + 'Looks like it could be a Threat Composer file, enabling ' + + element.textContent + + ' button', + ); + element.onclick = function () { + logDebugMessage(config, + 'Sending message with candicate JSON object back service worker / background script', + ); + browser.runtime.sendMessage(tcJSONCandidate); + }; + + switch (element.tagName) { //"Enable" button / anchor + case 'BUTTON': + (element as HTMLInputElement).disabled = false; + break; + case 'A': //Anchor + element.style.pointerEvents = 'auto'; + break; + } + + } else { + logDebugMessage(config, + "Does NOT look like it's a Threat Composer file, NOT enabling " + + element.textContent + + ' button', + ); + } +}; + +async function handleRawFile(config: TCConfig) { + const element = document.getElementsByTagName('pre'); + const tcButton = createTCButton(); + if (element) { + document.body.prepend(tcButton); + window.scrollTo(0, 0); //Scroll to top + } + logDebugMessage(config, 'Proactively attempting to retrieve candidate'); + const url = window.location.toString(); + await getTCJSONCandidate(url, tcButton, config); +}; + +function createTCButton() { + const tcButton = document.createElement('button'); + tcButton.textContent = 'View in Threat Composer'; + tcButton.disabled = true; + return tcButton; +} + +async function handleGitHubCodeViewer(gitHubState: TCGitHubState, config: TCConfig) { + var regExCheck = new RegExp(config.fileExtension); + if (window.location.href.match(regExCheck)) { + let element = document.querySelector('[aria-label="Copy raw content"]'); + if (window.location.href != gitHubState.previousUrl) { + //Handle GitHub being a SPA + gitHubState.previousUrl = window.location.href; + gitHubState.stopProcessing = false; + } + if (element && !gitHubState.stopProcessing) { + gitHubState.stopProcessing = true; + const rawButton = document.querySelector('[aria-label="Copy raw content"]'); + const tcButton = createTCButton(); + tcButton.setAttribute('type', 'button'); + tcButton.setAttribute('class', rawButton?.classList.toString()); + tcButton.setAttribute('data-size', 'small'); + rawButton?.before(tcButton); + logDebugMessage(config, 'Proactively attempting to retrieve candidate'); + const url = window.location + '?raw=1'; + await getTCJSONCandidate(url, tcButton, config); + } + } +}; + +async function handleAmazonCodeBrowser(codeBrowserState: TCCodeBrowserState, config: TCConfig) { + const element = document.getElementsByClassName('cs-Tabs__tab-header-actions'); + if (element && !codeBrowserState.stopProcessing) { + codeBrowserState.stopProcessing = true; + const fileActionsDiv = document.getElementById('file_actions'); + if (fileActionsDiv) { + const fileActionsButtonGroup = fileActionsDiv.getElementsByClassName('button_group')[0]; + const tcListItem = document.createElement('li'); + const tcAnchor = document.createElement('a'); + tcAnchor.setAttribute('class', 'minibutton'); + tcAnchor.textContent = 'View in Threat Composer'; + tcAnchor.style.pointerEvents = 'none'; + tcListItem.appendChild(tcAnchor); + fileActionsButtonGroup.appendChild(tcListItem); + logDebugMessage(config, 'Proactively attempting to retrieve candidate'); + const url = window.location + '?raw=1'; + await getTCJSONCandidate(url, tcAnchor, config); + } + } +}; + +async function handleCodeCatalystCodeViewer(codeCatalystState: TCCodeCatalystState, config: TCConfig) { + const element = document.getElementsByClassName( + 'cs-Tabs__tab-header-actions', + )[0]; + if (element && element.hasChildNodes() && !codeCatalystState.stopProcessing) { + codeCatalystState.stopProcessing = true; + const tcAnchor = document.createElement('a'); + const currentAnchor = element.firstChild; + tcAnchor.setAttribute( + 'class', + currentAnchor?.classList.toString(), + ); + + const currentSpan = currentAnchor?.firstChild; + + const tcSpan = document.createElement('span'); + tcSpan.setAttribute('class', currentSpan.classList.toString()); + tcSpan.textContent = 'View in Threat Composer'; + + tcAnchor.appendChild(tcSpan); + + tcAnchor.onclick = function () { + if (document.getElementById('raw-div')) { + const rawText = document.getElementById('raw-div')!.textContent; + if (rawText) { + const jsonObj: TCJSONSimplifiedSchema = JSON.parse(rawText); + logDebugMessage(config, + 'Sending message with candicate JSON object back service worker / background script', + ); + browser.runtime.sendMessage(jsonObj); + } + } + }; + + const actionsDiv = document.getElementsByClassName( + 'cs-Tabs__tab-header-actions', + )[0]; + actionsDiv.appendChild(tcAnchor); + } +}; + +export default defineContentScript({ + main() { + const gitHubState: TCGitHubState = { + previousUrl: '', + stopProcessing: false, + }; + + const codeBrowserState: TCCodeBrowserState = { + stopProcessing: false, + }; + + const codeCatalystState: TCCodeCatalystState = { + stopProcessing: false, + }; + + void (async function () { + + const tcConfig = await getExtensionConfig(); + + const config = { + childList: true, + subtree: true, + }; + + if ( + tcConfig.integrationRaw && + (window.location.href.match(/raw.githubusercontent.com/) || + window.location.href.match(/raw=1/)) + ) { + logDebugMessage(tcConfig, 'Based on URL or parameters, assuming raw file view'); + await handleRawFile(tcConfig); + } else if ( + tcConfig.integrationGitHubCodeBrowser && + window.location.href.match(/github.com/) + ) { + logDebugMessage(tcConfig, + 'URL is GitHub.com - Setting up mutation observer scoped to *://*.github.com/*' + + tcConfig.fileExtension + + '*', + ); + await handleGitHubCodeViewer(gitHubState, tcConfig); + let observerForGitHubCodeViewer = new MutationObserver( + () => handleGitHubCodeViewer(gitHubState, tcConfig), + ); + observerForGitHubCodeViewer.observe(document, config); + } else if ( + tcConfig.integrationCodeCatalystCodeBrowser && + window.location.href.match(/codecatalyst.aws/) + ) { + logDebugMessage(tcConfig, 'URL is codecatalyst.aws - Assuming code viewer'); + //Inject script + const s = document.createElement('script'); + s.src = browser.runtime.getURL('scriptInjectForCodeCatalyst.js'); + s.onload = function () { + this.remove(); + }; + (document.head || document.documentElement).appendChild(s); + let observerForCodeCatalystCodeViewer = new MutationObserver( + () => handleCodeCatalystCodeViewer(codeCatalystState, tcConfig), + ); + observerForCodeCatalystCodeViewer.observe(document.body, config); + } else if ( + tcConfig.integrationAmazonCodeBrowser && + window.location.href.match(/code.amazon.com/) + ) { + logDebugMessage(tcConfig, 'URL is code.amazon.com - Assuming code browser'); + await handleAmazonCodeBrowser(codeBrowserState, tcConfig); + let observerForAmazonCodeBrowser = new MutationObserver( + () => handleAmazonCodeBrowser(codeBrowserState, tcConfig), + ); + observerForAmazonCodeBrowser.observe(document.body, config); + } + })(); + }, +}); \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/popup/App.tsx b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/App.tsx new file mode 100644 index 00000000..0dffb55a --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/App.tsx @@ -0,0 +1,37 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ + +import { Spinner } from '@cloudscape-design/components'; +import { FC, useState, useEffect } from 'react'; +import { TCConfig, getExtensionConfig } from './config'; +import Config from './ConfigView'; +import { logDebugMessage } from '../../debugLogger'; + +const App: FC = () => { + const [config, setConfig] = useState(); + + useEffect(() => { + getExtensionConfig() + .then((loadedConfig) => setConfig(loadedConfig)) + .catch((error) => { + logDebugMessage({ debug: true } as any, error); + }); + }, []); + + return config ? : ; +}; + +export default App; diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/popup/ConfigView.tsx b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/ConfigView.tsx new file mode 100644 index 00000000..2876a77b --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/ConfigView.tsx @@ -0,0 +1,217 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ +import Box from '@cloudscape-design/components/box'; +import Button from '@cloudscape-design/components/button'; +import ColumnLayout from '@cloudscape-design/components/column-layout'; +import Container from '@cloudscape-design/components/container'; +import FormField from '@cloudscape-design/components/form-field'; +import Header from '@cloudscape-design/components/header'; +import Input from '@cloudscape-design/components/input'; +import Select from '@cloudscape-design/components/select'; +import SpaceBetween from '@cloudscape-design/components/space-between'; +import Toggle from '@cloudscape-design/components/toggle'; +import { FC } from 'react'; +import { + TCConfig, + useExtensionConfig, + ThreatComposerTarget, + DefaultConfig, +} from './config'; + +interface ConfigProps { + readonly initialConfig: TCConfig; +} + +// function createTargetOption(target: ThreatComposerTarget) { +// switch (target) { +// case ThreatComposerTarget.GITHUB_PAGES: +// return { +// value: ThreatComposerTarget.GITHUB_PAGES, +// label: "GitHub pages hosted version (threat-composer.github.io)", +// }; +// case ThreatComposerTarget.CUSTOM_HOST: +// return { +// value: ThreatComposerTarget.CUSTOM_HOST, +// label: "Self hosted version", +// }; +// case ThreatComposerTarget.BUILT_IN: +// default: +// return { +// value: ThreatComposerTarget.BUILT_IN, +// label: "Built-in, extension hosted version", +// }; +// } +// } + +const Config: FC = ({ initialConfig }) => { + const [config, setConfig] = useExtensionConfig(initialConfig); + + return ( + + +
+
Threat Composer extension
+ + View web accessible Threat Composer exports (.tc.json) with one + click + +
+ + +
+
'View Raw' file integration
+
+ +
+ + setConfig((prev) => ({ + ...prev, + integrationRaw: detail.checked, + })) + } + checked={config.integrationRaw} + > + Anywhere (*.tc.json) + +
+
+
+
+ + +
+
Code browser integrations
+
+
+ + setConfig((prev) => ({ + ...prev, + integrationGitHubCodeBrowser: detail.checked, + })) + } + checked={config.integrationGitHubCodeBrowser} + > + GitHub (github.com/*) + + + setConfig((prev) => ({ + ...prev, + integrationAmazonCodeBrowser: detail.checked, + })) + } + checked={config.integrationAmazonCodeBrowser} + > + Amazon Code (code.amazon.com/*) + + + setConfig((prev) => ({ + ...prev, + integrationCodeCatalystCodeBrowser: detail.checked, + })) + } + checked={config.integrationCodeCatalystCodeBrowser} + > + Amazon CodeCatalyst (codecatalyst.aws/*) + +
+
+
+ + +
+
Debug
+
+
+ + setConfig((prev) => ({ + ...prev, + debug: detail.checked, + })) + } + checked={config.debug} + > + Debug mode (output to console) + +
+
+
+ {/* + +
+
Open with
+
+
+ + setConfig((prev) => ({ + ...prev, + customUrl: detail.value, + })) + } + value={config.customUrl ?? ""} + placeholder="https://" + /> + + ) : null} +
+
+
*/} + + +

+ + + GitHub Project + + +

+
+
+
+ ); +}; + +export default Config; diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/popup/config.ts b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/config.ts new file mode 100644 index 00000000..78afad18 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/config.ts @@ -0,0 +1,74 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ +import { useState } from 'react'; +import { logDebugMessage } from '../../debugLogger'; + +export enum ThreatComposerTarget { + BUILT_IN = 'BUILT_IN', + GITHUB_PAGES = 'GITHUB_PAGES', + CUSTOM_HOST = 'CUSTOM_HOST', +} + +export interface TCConfig { + debug: boolean; + fileExtension: string; + integrationRaw: boolean; + integrationGitHubCodeBrowser: boolean; + integrationCodeCatalystCodeBrowser: boolean; + integrationAmazonCodeBrowser: boolean; + customUrl?: string; + target: ThreatComposerTarget; +} + +export const DefaultConfig: TCConfig = { + debug: false, + fileExtension: '.tc.json', + integrationRaw: true, + integrationGitHubCodeBrowser: true, + integrationCodeCatalystCodeBrowser: true, + integrationAmazonCodeBrowser: true, + target: ThreatComposerTarget.BUILT_IN, +}; + +export async function getExtensionConfig(): Promise { + const config = await browser.storage.local.get(['tcConfig']); //TODO: Consider if this could return an exeption or is it just undefined? + + if (config.tcConfig && Object.keys(config.tcConfig).length) { + return config.tcConfig; + } else { + return DefaultConfig; + } +} + +export function setExtensionConfig(config: TCConfig) { + browser.storage.local.set({ tcConfig: config }).then(() => { + logDebugMessage(config, 'Saved config to browser storage'); + }); +} + +export const useExtensionConfig = (defaultConfig: TCConfig) => { + const [value, setValue] = useState(defaultConfig); + + const handleValueChange = (doSetConfig: (prevConfig: TCConfig) => TCConfig) => { + setValue((prev) => { + const newConfig = doSetConfig(prev); + setExtensionConfig(newConfig); + return newConfig; + }); + }; + + return [value, handleValueChange] as const; +}; \ No newline at end of file diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/popup/index.html b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/index.html new file mode 100644 index 00000000..76462115 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/index.html @@ -0,0 +1,13 @@ + + + + + + Threat Composer extension + + + +
+ + + diff --git a/packages/threat-composer-app-browser-extension/src/entrypoints/popup/main.tsx b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/main.tsx new file mode 100644 index 00000000..536f1da7 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/entrypoints/popup/main.tsx @@ -0,0 +1,26 @@ +/** ******************************************************************************************************************* + Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"). + You may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ******************************************************************************************************************** */ +import React from 'react'; +import ReactDOM from 'react-dom'; +//import { BrowserRouter } from 'react-router-dom'; +import App from './App.tsx'; + +ReactDOM.render( + + + , + document.getElementById('root'), +); diff --git a/packages/threat-composer-app-browser-extension/src/public/scriptInjectForCodeCatalyst.js b/packages/threat-composer-app-browser-extension/src/public/scriptInjectForCodeCatalyst.js new file mode 100644 index 00000000..3b5e0615 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/public/scriptInjectForCodeCatalyst.js @@ -0,0 +1,41 @@ +let stop = false; +let raw_content = undefined; + +const debug = true; //TODO: Get this value from config. + +function logDebugMessage(msg) { + const debugPrefix = "ThreatComposerExtension: "; + if (debug) console.log(debugPrefix + msg); +} + +let handleCodeCatalystInject = async function () { + try { + element = document.querySelectorAll(".ace_editor")[0]; + document + .querySelectorAll(".ace_editor")[0] + .setAttribute("id", "ace-editor"); + editor = window.ace.edit("ace-editor"); + raw_content = await editor.getSession().getValue(); + } catch (err) { + //Do nothing + } + + if (raw_content && !stop) { + stop = true; + const debugPrefix = "ThreatComposerExtension: "; + logDebugMessage("Injecting contents of ace-editor into Div"); + const raw_div = document.createElement("div"); + raw_div.setAttribute("id", "raw-div"); + raw_div.hidden = true; + raw_div.textContent = raw_content; + document.body.appendChild(raw_div); + } +}; + +let observerForCodeCatalystInject = new MutationObserver( + handleCodeCatalystInject +); +observerForCodeCatalystInject.observe(document.body, { + childList: true, + subtree: true, +}); diff --git a/packages/threat-composer-app-browser-extension/src/public/scriptInjectForThreatComposer.js b/packages/threat-composer-app-browser-extension/src/public/scriptInjectForThreatComposer.js new file mode 100644 index 00000000..edec83e4 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/src/public/scriptInjectForThreatComposer.js @@ -0,0 +1,78 @@ +const browser = window.browser ? window.browser : window.chrome; + +const debug = true; //TODO: Get this value from config. + +function logDebugMessage(msg) { + const debugPrefix = "ThreatComposerExtension: "; + if (debug) console.log(debugPrefix + msg); +} + +function loadThreatModel(source) { + logDebugMessage("loadThreatModel: triggered" + " source:" + source); + if (window.threatcomposer.setCurrentWorkspaceData) { + logDebugMessage( + "loadThreatModel: window.threatcomposer.setCurrentWorkspaceData is NOT undefined" + ); + browser.storage.local + .get("threatModel") + .then((result) => { + const answer = result.threatModel; + if (answer != undefined) { + if (answer.schema) { + logDebugMessage(answer); + logDebugMessage( + "loadThreatModel: got valid JSON loading threat model, and disconnecting observer" + + " source:" + + source + ); + window.threatcomposer.setCurrentWorkspaceData(answer); + } else { + logDebugMessage( + "loadThreatModel: Did NOT get valid JSON loading threat model, NOT disconnecting observer" + + " source:" + + source + ); + } + } else { + logDebugMessage( + "loadThreatModel: Did NOT get JSON object, NOT disconnecting observer" + + " source:" + + source + ); + } + }) + .catch((error) => { + console.log(debugPrefix + error); + }); + } else { + logDebugMessage( + "loadThreatModel: window.threatcomposer.setCurrentWorkspaceData is undefined" + + " source:" + + source + ); + } +} + +logDebugMessage( + "Adding visibility event listener and mutation observer to trigger load of threat model" +); + +document.addEventListener("visibilitychange", (event) => { + loadThreatModel("visibility change"); +}); + +async function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + +document.addEventListener("DOMContentLoaded", async (event) => { + while (!window.threatcomposer.setCurrentWorkspaceData) { + logDebugMessage( + "Waiting for window.threatcomposer.setCurrentWorkspaceData" + ); + await sleep(50); + } + loadThreatModel("onload"); +}); diff --git a/packages/threat-composer-app-browser-extension/tsconfig.dev.json b/packages/threat-composer-app-browser-extension/tsconfig.dev.json new file mode 100644 index 00000000..8b4429ff --- /dev/null +++ b/packages/threat-composer-app-browser-extension/tsconfig.dev.json @@ -0,0 +1,40 @@ +// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +{ + "compilerOptions": { + "alwaysStrict": true, + "declaration": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "inlineSourceMap": true, + "inlineSources": true, + "lib": [ + "dom", + "dom.iterable" + ], + "module": "CommonJS", + "noEmitOnError": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": true, + "target": "ES2019", + "jsx": "react-jsx" + }, + "include": [ + ".projenrc.js", + "src/**/*.ts", + "test/**/*.ts", + "src", + ".wxt/types" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/packages/threat-composer-app-browser-extension/tsconfig.json b/packages/threat-composer-app-browser-extension/tsconfig.json new file mode 100644 index 00000000..03a705b4 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/tsconfig.json @@ -0,0 +1,38 @@ +// ~~ Generated by projen. To modify, edit .projenrc.js and run "npx projen". +{ + "compilerOptions": { + "rootDir": "src", + "outDir": "lib", + "alwaysStrict": true, + "declaration": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "inlineSourceMap": true, + "inlineSources": true, + "lib": [ + "dom", + "dom.iterable" + ], + "module": "CommonJS", + "noEmitOnError": false, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "strict": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "stripInternal": true, + "target": "ES2019", + "jsx": "react-jsx" + }, + "include": [ + "src/**/*.ts", + "src", + ".wxt/types" + ], + "exclude": [] +} diff --git a/packages/threat-composer-app-browser-extension/wxt.config.ts b/packages/threat-composer-app-browser-extension/wxt.config.ts new file mode 100644 index 00000000..44b2ec65 --- /dev/null +++ b/packages/threat-composer-app-browser-extension/wxt.config.ts @@ -0,0 +1,51 @@ +import { defineConfig } from 'wxt'; +import react from '@vitejs/plugin-react'; +import copy from 'rollup-plugin-copy'; + +const tcScriptInjectForThreatComposer = 'scriptInjectForThreatComposer.js' + +export default defineConfig({ + vite: () => ({ + build: { + emptyOutDir: false + }, + plugins: [ + react(), + copy({ + targets: [{ + src: '../threat-composer-app/build/browser-extension/index.html', + dest: ['./.output/chrome-mv3', './.output/firefox-mv2'], + transform: (contents, filename) => contents.toString().replace('<\/body><\/html>', '