-
Notifications
You must be signed in to change notification settings - Fork 0
Dev #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Removed flickers when blocked page got displayed (you can clearly see text fields getting updated). - Popup display used a temporary white background color, used theme color instead tro fix the white flash effect (especially visible with dark theme).
commit 638c177 Merge: 4f8d57e 650a780 Author: KelvinTegelaar <[email protected]> Date: Tue Oct 21 19:46:48 2025 +0200 Merge pull request CyberDrain#90 from PeakeIT/main commit 650a780 Author: Brandon Rutledge <[email protected]> Date: Thu Oct 16 18:12:59 2025 -0400 fix: urlAllowlist registry entries to be in the correct format and Edge pinning in the ADMX
Added test pages for local file testing/detection Added console log dev setting performance Added regex caching performance Added dom caching performance
Test Pages and Performance Improvements
json escaping for regexes
Fixed bug where custom rules URLs reverted to defaults after save. - Save only user overrides to local storage, not entire merged config - Sanitize empty URLs to fall back to defaults - Respect enterprise policy precedence over user settings - Add config reload capability to DetectionRulesManager - Add comprehensive test suite (13 tests, all passing) Closes CyberDrain#87
fix: custom detection rules URL not persisting
- Removed flickers when blocked page got displayed (you can clearly see text fields getting updated). - Popup display used a temporary white background color, used theme color instead tro fix the white flash effect (especially visible with dark theme).
Added test pages for local file testing/detection Added console log dev setting performance Added regex caching performance Added dom caching performance
json escaping for regexes
Fixed bug where custom rules URLs reverted to defaults after save. - Save only user overrides to local storage, not entire merged config - Sanitize empty URLs to fall back to defaults - Respect enterprise policy precedence over user settings - Add config reload capability to DetectionRulesManager - Add comprehensive test suite (13 tests, all passing) Closes CyberDrain#87
- added test script for quick dev setup on registry settings - added generic webhook handling with actions - added report false positive button with success/error logic - added github to the default rules to prevent detection
Added refreshToken input to Google Refresh Token workflow. Signed-off-by: John Duprey <[email protected]>
Added permissions for content write access in jobs. Signed-off-by: John Duprey <[email protected]>
This script removes specific Chrome and Edge extension settings from the Windows registry, including managed storage and extension settings keys. Signed-off-by: Roel van der Wegen <[email protected]>
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: cardinalby/export-env-action@66657b34899a2d695434ed060d9f2215db9b4035 | ||
| with: | ||
| envFile: './.github/workflows/constants.env' | ||
| expand: true | ||
|
|
||
| - name: Build, test and pack to zip | ||
| id: build | ||
| uses: ./.github/workflows/actions/build-test-pack | ||
| with: | ||
| # pack zip only for pull requests or workflow_dispatch events | ||
| doNotPackZip: ${{ github.event_name == 'push' && 'true' || 'false'}} | ||
|
|
||
| - name: Upload zip file artifact | ||
| if: github.event_name != 'push' | ||
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 | ||
| with: | ||
| name: ${{ env.ZIP_FILE_NAME }} | ||
| path: ${{ env.ZIP_FILE_PATH }} No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
The best way to fix the problem is to add a permissions block at the root of the workflow file (just under the name and prior to the on: block, or right after the on: block), specifying only the minimum permissions required. In most cases, contents: read is sufficient for build/test jobs. If all steps in this workflow only need to checkout code and upload artifacts, contents: read suffices. Add this block to the top of .github/workflows/build-and-test.yml. No other steps, methods, imports, or variable definitions are required.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: Build and test | ||
| permissions: | ||
| contents: read | ||
| on: | ||
| pull_request: | ||
| push: |
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: cardinalby/google-api-fetch-token-action@24c99245e2a2494cc4c4b1037203d319a184b15b | ||
| with: | ||
| clientId: ${{ secrets.G_CLIENT_ID }} | ||
| clientSecret: ${{ secrets.G_CLIENT_SECRET }} | ||
| refreshToken: ${{ secrets.G_REFRESH_TOKEN }} |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To fix the problem, you need to add a permissions block to the workflow. Since the shown job only fetches a Google API token and does not interact with the GitHub API for creating/modifying content or PRs, it needs a minimal permissions grant—contents: read or possibly even none in some cases. The safest fix is to add permissions: contents: read at the workflow root, which will ensure the job token can only read repository contents and cannot perform any write operations. This block should be inserted just after the workflow name and before the on: key.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: Google Refresh Token | ||
| permissions: | ||
| contents: read | ||
| on: | ||
| schedule: | ||
| - cron: '0 3 2 * *' # At 03:00 on day-of-month 2 |
| runs-on: ubuntu-latest | ||
| environment: ${{ github.event.inputs.environment }} | ||
| outputs: | ||
| result: ${{ steps.webStorePublish.outcome }} | ||
| releaseUploadUrl: ${{ steps.getZipAsset.outputs.releaseUploadUrl }} | ||
| steps: | ||
| - name: Get the next attempt number | ||
| id: getNextAttemptNumber | ||
| uses: cardinalby/js-eval-action@b34865f1d9cfdf35356013627474857cfe0d5091 | ||
| env: | ||
| attemptNumber: ${{ github.event.inputs.attemptNumber }} | ||
| maxAttempts: ${{ github.event.inputs.maxAttempts }} | ||
| with: | ||
| expression: | | ||
| { | ||
| const | ||
| attempt = parseInt(env.attemptNumber), | ||
| max = parseInt(env.maxAttempts); | ||
| assert(attempt && max && max >= attempt); | ||
| return attempt < max ? attempt + 1 : ''; | ||
| } | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: cardinalby/export-env-action@66657b34899a2d695434ed060d9f2215db9b4035 | ||
| with: | ||
| envFile: './.github/workflows/constants.env' | ||
| expand: true | ||
|
|
||
| - name: Obtain packed zip | ||
| id: getZipAsset | ||
| uses: ./.github/workflows/actions/get-zip-asset | ||
| with: | ||
| githubToken: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Fetch Google API access token | ||
| id: fetchAccessToken | ||
| uses: cardinalby/google-api-fetch-token-action@24c99245e2a2494cc4c4b1037203d319a184b15b | ||
| with: | ||
| clientId: ${{ secrets.G_CLIENT_ID }} | ||
| clientSecret: ${{ secrets.G_CLIENT_SECRET }} | ||
| refreshToken: ${{ secrets.G_REFRESH_TOKEN }} | ||
|
|
||
| - name: Upload to Google Web Store | ||
| id: webStoreUpload | ||
| continue-on-error: true | ||
| uses: cardinalby/webext-buildtools-chrome-webstore-upload-action@8db7a005529498d95d3e2e0166f6f4050d2b96a5 | ||
| with: | ||
| zipFilePath: ${{ env.ZIP_FILE_PATH }} | ||
| extensionId: ${{ secrets.G_EXTENSION_ID }} | ||
| apiAccessToken: ${{ steps.fetchAccessToken.outputs.accessToken }} | ||
| waitForUploadCheckCount: 10 | ||
| waitForUploadCheckIntervalMs: 180000 # 3 minutes | ||
|
|
||
| # Schedule a next attempt if store refused to accept new version because it | ||
| # still has a previous one in review | ||
| - name: Start the next attempt with the delay | ||
| uses: aurelien-baudet/workflow-dispatch@93e95b157d791ae7f42aef8f8a0d3d723eba1c31 # pin@v2 | ||
| if: | | ||
| steps.getNextAttemptNumber.outputs.result && | ||
| steps.webStoreUpload.outputs.inReviewError == 'true' | ||
| with: | ||
| workflow: ${{ github.workflow }} | ||
| token: ${{ secrets.WORKFLOWS_TOKEN }} | ||
| wait-for-completion: false | ||
| inputs: | | ||
| { | ||
| "attemptNumber": "${{ steps.getNextAttemptNumber.outputs.result }}", | ||
| "maxAttempts": "${{ github.event.inputs.maxAttempts }}", | ||
| "environment": "12hoursDelay" | ||
| } | ||
| - name: Abort on unrecoverable upload error | ||
| if: | | ||
| !steps.webStoreUpload.outputs.newVersion && | ||
| steps.webStoreUpload.outputs.sameVersionAlreadyUploadedError != 'true' | ||
| run: exit 1 | ||
|
|
||
| - name: Publish on Google Web Store | ||
| id: webStorePublish | ||
| if: | | ||
| steps.webStoreUpload.outputs.newVersion || | ||
| steps.webStoreUpload.outputs.sameVersionAlreadyUploadedError == 'true' | ||
| uses: cardinalby/webext-buildtools-chrome-webstore-publish-action@d39ebd4ab4ea4b44498bf5fc34d4b3db7706f1ed | ||
| with: | ||
| extensionId: ${{ secrets.G_EXTENSION_ID }} | ||
| apiAccessToken: ${{ steps.fetchAccessToken.outputs.accessToken }} | ||
|
|
||
| download-published-crx: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To fix the problem, add an explicit permissions block at the workflow root (just after the name: and before on:) to set the least privilege required for the jobs. A minimal safe starting point is contents: read. If any jobs require elevated permissions (such as uploading release assets, which may need contents: write), you can specify more granular permissions in those jobs, but for this fix, set permissions: contents: read at the top level. This will restrict the GITHUB_TOKEN to read-only by default for all jobs unless overridden.
In .github/workflows/publish-on-chrome-webstore.yml, add the following at the top:
permissions:
contents: readThis change does not alter the functionality of the workflow, but rather secures it by defining the permissions scope explicitly.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: publish-on-chrome-web-store | ||
| permissions: | ||
| contents: read | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: |
| needs: publish-on-webstore | ||
| if: needs.publish-on-webstore.outputs.result == 'success' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: cardinalby/export-env-action@66657b34899a2d695434ed060d9f2215db9b4035 | ||
| with: | ||
| envFile: './.github/workflows/constants.env' | ||
| expand: true | ||
|
|
||
| - name: Download published crx file | ||
| id: gWebStoreDownloadCrx | ||
| uses: cardinalby/webext-buildtools-chrome-webstore-download-crx-action@7de7ffb52fac6255a343c5e982871eb23cbee253 | ||
| with: | ||
| extensionId: ${{ secrets.G_EXTENSION_ID }} | ||
| crxFilePath: ${{ env.WEBSTORE_CRX_FILE_PATH }} | ||
|
|
||
| - name: Upload webstore published crx release asset | ||
| if: needs.publish-on-webstore.outputs.releaseUploadUrl | ||
| uses: actions/upload-release-asset@v1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| upload_url: ${{ needs.publish-on-webstore.outputs.releaseUploadUrl }} | ||
| asset_path: ${{ env.WEBSTORE_CRX_FILE_PATH }} | ||
| asset_name: ${{ env.WEBSTORE_CRX_FILE_NAME }} | ||
| asset_content_type: application/x-chrome-extension | ||
|
|
||
| - name: Upload webstore crx file artifact to workflow | ||
| if: '!needs.publish-on-webstore.outputs.releaseUploadUrl' | ||
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 | ||
| with: | ||
| name: ${{ env.WEBSTORE_CRX_FILE_NAME }} | ||
| path: ${{ env.WEBSTORE_CRX_FILE_PATH }} |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To address this issue, add a permissions: block to the workflow YAML (.github/workflows/publish-on-chrome-webstore.yml). The best practice is to add the block at the top level, so it applies to all jobs in the workflow, unless some jobs specifically require different, broader permissions. In this case, since the jobs appear to primarily read repository contents and upload release artifacts (actions which require contents: read and contents: write), you may set contents: read at workflow level as the starting point, then add broader permissions for jobs that require them (e.g., download-published-crx for uploading release assets may need contents: write). For a minimal fix, simply add permissions: contents: read at the workflow level.
This change should be made at the beginning of the workflow file, after the name: and before the on: block, as shown in the example. No additional dependencies or method changes are required.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: publish-on-chrome-web-store | ||
| permissions: | ||
| contents: read | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: |
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: cardinalby/export-env-action@66657b34899a2d695434ed060d9f2215db9b4035 | ||
| with: | ||
| envFile: './.github/workflows/constants.env' | ||
| expand: true | ||
|
|
||
| - name: Obtain packed zip | ||
| uses: ./.github/workflows/actions/get-zip-asset | ||
| with: | ||
| githubToken: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Deploy to Edge Addons | ||
| uses: wdzeng/edge-addon@fe088a3bb9bf7c3f1cab08df6269664b9f7bf4fd # [email protected] | ||
| with: | ||
| product-id: ${{ secrets.EDGE_PRODUCT_ID }} | ||
| zip-path: ${{ env.ZIP_FILE_PATH }} | ||
| client-id: ${{ secrets.EDGE_CLIENT_ID }} | ||
| client-secret: ${{ secrets.EDGE_CLIENT_SECRET }} | ||
| access-token-url: ${{ secrets.EDGE_ACCESS_TOKEN_URL }} No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
To fix this problem, you should add an explicit permissions block at either the workflow or job level. Since all jobs here are relevant to publishing/deploying (no mention of multiple jobs or jobs requiring different sets of permissions), you can specify the block at the top level for clarity and security. The minimal required permission for read-only repository access is contents: read. However, if any step of the job needs more (for example, to create releases, upload artifacts, or interact with pull requests), you may need to extend these. According to the steps shown—where the job checks out the repository and accesses secrets, but does not modify repository contents—contents: read should be sufficient.
You will add the following to the top of the workflow file, after the name: line, to constrain the GITHUB_TOKEN permissions:
permissions:
contents: readThis should be line 2, shifting all subsequent lines down by one.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: publish-on-edge-add-ons | ||
| permissions: | ||
| contents: read | ||
| on: | ||
| workflow_dispatch: | ||
| jobs: |
| if: github.ref_type == 'tag' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: cardinalby/export-env-action@66657b34899a2d695434ed060d9f2215db9b4035 | ||
| with: | ||
| envFile: './.github/workflows/constants.env' | ||
| expand: true | ||
|
|
||
| - name: Look for existing release | ||
| id: getRelease | ||
| uses: cardinalby/git-get-release-action@cedef2faf69cb7c55b285bad07688d04430b7ada | ||
| continue-on-error: true | ||
| with: | ||
| tag: ${{ github.ref_name }} | ||
| env: | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
|
|
||
| - name: Build, test and pack to zip | ||
| id: buildPack | ||
| if: steps.getRelease.outcome != 'success' | ||
| uses: ./.github/workflows/actions/build-test-pack | ||
|
|
||
| - name: Create Release | ||
| id: createRelease | ||
| if: steps.getRelease.outcome != 'success' | ||
| uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37 # pin@v1 | ||
| with: | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| draft: 'true' | ||
|
|
||
| - name: Upload zip asset to the release | ||
| if: steps.getRelease.outcome != 'success' | ||
| uses: actions/upload-release-asset@v1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| upload_url: ${{ steps.createRelease.outputs.upload_url }} | ||
| asset_path: ${{ env.ZIP_FILE_PATH }} | ||
| asset_name: ${{ env.ZIP_FILE_NAME }} | ||
| asset_content_type: application/zip | ||
|
|
||
| # Should trigger build-assets-on-release.yml | ||
| - name: Publish release | ||
| if: steps.getRelease.outcome != 'success' | ||
| uses: eregon/publish-release@c2c0552ef2dd8209aea2a95c940a156eb8f6e9c1 # pin@v1 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.WORKFLOWS_TOKEN }} | ||
| with: | ||
| release_id: ${{ steps.createRelease.outputs.id }} | ||
|
|
||
| - name: Publish on Chrome Webstore | ||
| uses: benc-uk/workflow-dispatch@4c044c1613fabbe5250deadc65452d54c4ad4fc7 # pin@v1 | ||
| with: | ||
| workflow: publish-on-chrome-web-store | ||
| token: ${{ secrets.WORKFLOWS_TOKEN }} | ||
|
|
||
| - name: Publish on Edge Add-ons | ||
| uses: benc-uk/workflow-dispatch@4c044c1613fabbe5250deadc65452d54c4ad4fc7 # pin@v1 | ||
| with: | ||
| workflow: publish-on-edge-add-ons | ||
| token: ${{ secrets.WORKFLOWS_TOKEN }} No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
The best way to fix the problem is to explicitly declare a top-level permissions block in the workflow YAML file, granting the least amount of privilege required for the workflow to succeed. For most of the steps in this workflow, write permission to contents is required (e.g., creating releases, uploading assets). In general, start with contents: write at the workflow level. If some jobs/steps need even less, consider scoping permissions to jobs; however, no evidence is shown here for finer granularity. Add the block right after the workflow name and before the on: key, following YAML conventions, as per GitHub Actions documentation. No additional imports or external libraries are required.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: Release and publish on tag | ||
| permissions: | ||
| contents: write | ||
| on: | ||
| push: | ||
| tags: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces comprehensive webhook functionality, test infrastructure, improved configuration management, and enhanced development/deployment tooling for the Check extension.
- Adds a unified webhook system supporting multiple event types (detection alerts, false positives, page blocks, rogue app detection)
- Implements test infrastructure with Chrome API mocks and configuration persistence tests
- Refactors configuration management to centralize
customRulesUrland improve user settings persistence - Enhances deployment with GitHub Actions workflows and enterprise policy updates
Reviewed Changes
Copilot reviewed 39 out of 39 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/modules/webhook-manager.js | New webhook management system with unified payload structure for all event types |
| scripts/modules/config-manager.js | Refactored config persistence to save only user overrides and migrate legacy settings |
| scripts/modules/detection-rules-manager.js | Added configuration reload functionality |
| scripts/content.js | Performance optimizations with regex caching, page source caching, and webhook integration |
| scripts/background.js | Integrated webhook manager and delegated webhook sending to centralized manager |
| scripts/blocked.js | Added false positive reporting functionality with webhook support |
| tests/config-persistence.test.js | New test suite for configuration persistence and enterprise policy precedence |
| tests/helpers/chrome-mock.js | Chrome API mock implementation for testing |
| tests/helpers/logger-mock.js | Logger mock for test environment |
| test-pages/*.html | Test pages for manual phishing detection validation |
| options/options.html | Added generic webhook configuration UI |
| options/options.js | Integrated webhook settings management |
| rules/detection-rules.json | Updated regex patterns with escaped forward slashes and improved detection logic |
| manifest.json | Added file:// protocol support for local testing |
| config/managed_schema.json | Added genericWebhook schema for enterprise policies |
| docs/webhooks.md | Comprehensive webhook documentation with payload examples |
| docs/settings/general.md | Documentation for false positive webhook configuration |
| enterprise/admx/en-US/Check-Extension.adml | Formatting improvements and companyURL policy addition |
| enterprise/*.ps1 | New PowerShell scripts for testing and removal of extension policies |
| .github/workflows/*.yml | New CI/CD workflows for building, testing, and publishing releases |
| blocked.html | Added false positive reporting button and anti-flicker loading state |
| popup/popup.css | Theme-aware loading screen colors |
| package.json | Added test scripts for running test suites |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Check if false positive webhook is configured and show button accordingly | ||
| const falsePositiveBtn = document.getElementById("reportFalsePositiveBtn"); | ||
| const genericWebhook = storageResult.genericWebhook; | ||
| if (genericWebhook && genericWebhook.enabled && genericWebhook.url) { | ||
| const events = genericWebhook.events || []; | ||
| if (events.includes("false_positive_report")) { | ||
| console.log("False positive webhook configured, showing report button"); | ||
| webhookConfig = { url: genericWebhook.url }; | ||
| if (falsePositiveBtn) { | ||
| falsePositiveBtn.style.display = "inline-block"; | ||
| } | ||
| return; | ||
| } | ||
| } | ||
| console.log("No false positive webhook configured, hiding report button"); | ||
| if (falsePositiveBtn) { | ||
| falsePositiveBtn.style.display = "none"; | ||
| } |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The webhook URL and enabled state are not validated before sending the webhook. The code should validate that the URL is a valid HTTPS URL to prevent accidentally sending sensitive detection data over insecure HTTP connections.
Add validation like:
if (genericWebhook.url && !genericWebhook.url.startsWith('https://')) {
console.error("Webhook URL must use HTTPS");
return;
}| async function reportFalsePositive() { | ||
| console.log("reportFalsePositive function called"); | ||
|
|
||
| const reportBtn = document.getElementById("reportFalsePositiveBtn"); | ||
|
|
||
| if (!webhookConfig || !webhookConfig.url) { | ||
| console.error("No webhook configured"); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| reportBtn.disabled = true; | ||
| reportBtn.textContent = "Sending..."; | ||
| reportBtn.style.background = "#6b7280"; | ||
| reportBtn.style.color = "white"; | ||
|
|
||
| const payload = { | ||
| version: "1.0", | ||
| type: "false_positive_report", | ||
| timestamp: new Date().toISOString(), | ||
| source: "Check Extension", | ||
| extensionVersion: chrome.runtime.getManifest().version, | ||
| data: { | ||
| reportedUrl: document.getElementById("blockedUrl").textContent, | ||
| reportedReason: document.getElementById("blockReason").textContent, | ||
| reportTimestamp: new Date().toISOString(), | ||
| userAgent: navigator.userAgent, | ||
| browserInfo: { | ||
| platform: navigator.platform, | ||
| language: navigator.language, | ||
| vendor: navigator.vendor, | ||
| cookiesEnabled: navigator.cookieEnabled, | ||
| onLine: navigator.onLine | ||
| }, | ||
| screenResolution: { | ||
| width: window.screen.width, | ||
| height: window.screen.height, | ||
| availWidth: window.screen.availWidth, | ||
| availHeight: window.screen.availHeight, | ||
| colorDepth: window.screen.colorDepth | ||
| }, | ||
| detectionDetails: globalDetectionDetails || {}, | ||
| userComments: null | ||
| } | ||
| }; | ||
|
|
||
| console.log("Sending false positive report to:", webhookConfig.url); | ||
| console.log("Report payload:", payload); | ||
|
|
||
| const response = await fetch(webhookConfig.url, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| "X-Webhook-Type": "false_positive_report", | ||
| "X-Webhook-Version": "1.0" | ||
| }, | ||
| body: JSON.stringify(payload) | ||
| }); | ||
|
|
||
| if (response.ok) { | ||
| console.log("False positive report sent successfully"); | ||
| reportBtn.textContent = "Report Sent Successfully"; | ||
| reportBtn.style.background = "#16a34a"; | ||
| reportBtn.style.color = "white"; | ||
| } else { | ||
| console.warn("False positive report failed with HTTP status:", response.status, response.statusText); | ||
| throw new Error(`HTTP ${response.status}: ${response.statusText}`); | ||
| } | ||
| } catch (error) { | ||
| console.error("Failed to send false positive report:", error); | ||
| reportBtn.textContent = `Failed: ${error.message}`; | ||
| reportBtn.style.background = "#dc2626"; | ||
| reportBtn.style.color = "white"; | ||
| } | ||
| } |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reportFalsePositive function sends potentially sensitive detection details including page content, browser information, and screen resolution to an arbitrary webhook URL. There's no user consent or warning about what data is being sent when they click the "Report False Positive" button.
Consider adding a confirmation dialog that clearly explains what data will be sent, or providing a privacy notice near the button.
| } | ||
| analysis.sheets.push(sheetInfo); | ||
| } | ||
| } catch (e) {} |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty catch blocks silently swallow errors, making debugging difficult. The webhook sending failures in the content script use .catch(err => { logger.warn(...) }) pattern, but here the error is completely ignored.
Consider at least logging the error:
} catch (e) {
logger.warn("Failed to analyze stylesheets:", e);
}| } catch (e) {} | |
| } catch (e) { | |
| logger.warn("Failed to analyze stylesheets:", e); | |
| } |
| genericWebhook: { | ||
| enabled: this.elements.genericWebhookEnabled?.checked || false, | ||
| url: this.elements.genericWebhookUrl?.value || "", | ||
| events: [ | ||
| "detection_alert", | ||
| "false_positive_report", | ||
| "page_blocked", | ||
| "rogue_app_detected", | ||
| "threat_detected", | ||
| "validation_event" | ||
| ].filter(eventType => | ||
| document.getElementById(`webhookEvent_${eventType}`)?.checked | ||
| ) | ||
| }, |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The generic webhook configuration lacks input validation in the UI. The webhook URL should be validated to ensure it's a valid HTTPS URL before saving. Currently, users could enter an invalid URL or an insecure HTTP URL, which would cause runtime errors or security issues.
Add URL validation in the save configuration logic similar to how other URLs are validated in the codebase.
| global.fetch = async () => ({ | ||
| ok: false, | ||
| status: 404 | ||
| }); |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The test uses a mock fetch that always returns ok: false, status: 404. This setup is repeated in multiple test suites, creating code duplication. Consider extracting this into a helper function in the test setup or creating a reusable mock fetch fixture.
For example:
function createMockFetch(response = { ok: false, status: 404 }) {
return async () => response;
}| "^https:\\/\\/login\\.microsoftonline\\.(com|us)$", | ||
| "^https:\\/\\/login\\.microsoft\\.com$", | ||
| "^https:\\/\\/login\\.microsoft\\.net$", | ||
| "^https:\\/\\/login\\.windows\\.net$", | ||
| "^https:\\/\\/login\\.partner\\.microsoftonline\\.cn$", | ||
| "^https:\\/\\/login\\.live\\.com$" |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex patterns in the detection rules JSON file use escaped forward slashes (\/) which are unnecessary in JSON strings. JSON does not require escaping forward slashes, and while it's technically valid, it adds unnecessary complexity and makes the patterns harder to read.
For example, "^https:\\/\\/login\\.microsoftonline\\.(com|us)$" should be "^https://login\\.microsoftonline\\.(com|us)$".
Consider simplifying these patterns for better maintainability.
| { | ||
| "id": "phi_006", | ||
| "pattern": "(?=.*(?:microsoft|office|365))(?=.*(?:login|password|signin))(?=.*form.*action)(?!.*login\\.microsoftonline\\.com)(?!.*\\.auth/login/)(?!.*azure\\s+static\\s+web\\s+apps)(?!.*easy\\s+auth)", | ||
| "pattern": "(?:microsoft|office|365).{0,2000}(?:login|password|signin).{0,500}form.{0,200}action(?!.*login\\.microsoftonline\\.com)(?!.*\\.auth/login/)(?!.*azure\\s+static\\s+web\\s+apps)(?!.*easy\\s+auth)", |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex pattern uses a greedy quantifier .{0,2000} which could cause performance issues when matching against large HTML documents. Consider using a non-greedy quantifier .{0,2000}? or a more specific pattern to improve regex performance and prevent potential regex denial-of-service (ReDoS) scenarios.
| "pattern": "(?:microsoft|office|365).{0,2000}(?:login|password|signin).{0,500}form.{0,200}action(?!.*login\\.microsoftonline\\.com)(?!.*\\.auth/login/)(?!.*azure\\s+static\\s+web\\s+apps)(?!.*easy\\s+auth)", | |
| "pattern": "(?:microsoft|office|365).{0,2000}?(?:login|password|signin).{0,500}form.{0,200}action(?!.*login\\.microsoftonline\\.com)(?!.*\\.auth/login/)(?!.*azure\\s+static\\s+web\\s+apps)(?!.*easy\\s+auth)", |
| "content_scripts": [ | ||
| { | ||
| "matches": ["http://*/*", "https://*/*"], | ||
| "matches": ["http://*/*", "https://*/*", "file:///*/*"], |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The manifest.json adds support for "file:///*/*" URLs in content scripts. This allows the extension to run on local file:// URLs, which could be a security concern as it gives the extension access to the user's local file system content when viewing HTML files locally.
Consider whether this is truly necessary for the extension's functionality, or if it should be limited to specific use cases (like developer testing). If it's only for testing, consider documenting this clearly or providing a separate development manifest.
| "matches": ["http://*/*", "https://*/*", "file:///*/*"], | |
| "matches": ["http://*/*", "https://*/*"], |
| function analyzeStylesheets() { | ||
| if (cachedStylesheetAnalysis) return cachedStylesheetAnalysis; | ||
| const analysis = { hasMicrosoftCSS: false, cssContent: "", sheets: [] }; | ||
| try { | ||
| const styleSheets = Array.from(document.styleSheets); | ||
| for (const sheet of styleSheets) { | ||
| const sheetInfo = { href: sheet.href || "inline" }; | ||
| if (sheet.href?.match(/msauth|msft|microsoft/i)) { | ||
| analysis.hasMicrosoftCSS = true; | ||
| } | ||
| try { | ||
| if (sheet.cssRules) { | ||
| analysis.cssContent += | ||
| Array.from(sheet.cssRules) | ||
| .map((r) => r.cssText) | ||
| .join(" ") + " "; | ||
| sheetInfo.accessible = true; | ||
| } | ||
| } catch (e) { | ||
| sheetInfo.accessible = false; | ||
| } | ||
| analysis.sheets.push(sheetInfo); | ||
| } | ||
| } catch (e) {} | ||
| cachedStylesheetAnalysis = analysis; | ||
| return analysis; | ||
| } | ||
|
|
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused function analyzeStylesheets.
| function analyzeStylesheets() { | |
| if (cachedStylesheetAnalysis) return cachedStylesheetAnalysis; | |
| const analysis = { hasMicrosoftCSS: false, cssContent: "", sheets: [] }; | |
| try { | |
| const styleSheets = Array.from(document.styleSheets); | |
| for (const sheet of styleSheets) { | |
| const sheetInfo = { href: sheet.href || "inline" }; | |
| if (sheet.href?.match(/msauth|msft|microsoft/i)) { | |
| analysis.hasMicrosoftCSS = true; | |
| } | |
| try { | |
| if (sheet.cssRules) { | |
| analysis.cssContent += | |
| Array.from(sheet.cssRules) | |
| .map((r) => r.cssText) | |
| .join(" ") + " "; | |
| sheetInfo.accessible = true; | |
| } | |
| } catch (e) { | |
| sheetInfo.accessible = false; | |
| } | |
| analysis.sheets.push(sheetInfo); | |
| } | |
| } catch (e) {} | |
| cachedStylesheetAnalysis = analysis; | |
| return analysis; | |
| } |
No description provided.