Skip to content

DuoHacker Extension#9

Open
QikseekDev wants to merge 14 commits into
not2pixel:mainfrom
QikseekDev:main
Open

DuoHacker Extension#9
QikseekDev wants to merge 14 commits into
not2pixel:mainfrom
QikseekDev:main

Conversation

@QikseekDev
Copy link
Copy Markdown

This PR adds a Chrome extension + its source code that loads the DuoHacker userscript on Duolingo web.

The extension acts as a lightweight loader and does not modify the userscript itself. It simply injects the upstream script on supported Duolingo domains.

Key points:

Loads official upstream userscript as-is
No modification or obfuscation of core script logic
Limited permissions (Duolingo domains only)
Public repository for full transparency
Updates are handled through versioned commits

@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Reorganize DuoHacker extension with Greasemonkey API polyfill

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Reorganizes extension files into extension/source/ directory structure
• Implements Greasemonkey API polyfill for userscript compatibility
• Fetches and executes DuoHacker userscript from GitHub repository
• Configures Chrome extension manifest with Duolingo domain permissions
Diagram
flowchart LR
  A["Content Script<br/>content.js"] -->|"Injects"| B["Inject Script<br/>inject.js"]
  B -->|"Polyfills GM API"| C["Greasemonkey<br/>Functions"]
  B -->|"Fetches & Executes"| D["DuoHacker Userscript<br/>GitHub"]
  E["Manifest v3<br/>manifest.json"] -->|"Configures"| A
  E -->|"Defines Permissions"| F["Duolingo Domains<br/>+ Resources"]

Loading

Grey Divider

File Changes

1. extension/source/content.js ✨ Enhancement +10/-0

Content script for userscript injection

• Creates and injects a script element that loads inject.js
• Removes the script tag after loading completes
• Logs confirmation message to console

extension/source/content.js


2. extension/source/inject.js ✨ Enhancement +298/-0

Greasemonkey API polyfill and userscript loader

• Implements complete Greasemonkey API polyfill with localStorage-based storage
• Provides GM functions: getValue, setValue, deleteValue, listValues,
 addValueChangeListener, removeValueChangeListener
• Implements GM_xmlhttpRequest using Fetch API with support for different response types
• Fetches and executes DuoHacker userscript from GitHub repository
• Exposes both modern GM object and legacy GM_* functions to window scope

extension/source/inject.js


3. extension/source/manifest.json ⚙️ Configuration changes +81/-0

Chrome extension manifest configuration

• Defines Chrome extension manifest v3 configuration
• Specifies content script injection on Duolingo domains with document_end timing
• Declares host permissions for Duolingo, GitHub, Google Fonts, and related services
• Marks inject.js as web-accessible resource for content script injection
• Includes extension metadata with name, version, and feature description

extension/source/manifest.json


View more (1)
4. extension/temp Miscellaneous +1/-0

Temporary placeholder file

• Empty placeholder file

extension/temp


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 27, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Invalid manifest JSON ✓ Resolved 🐞 Bug ≡ Correctness
Description
extension/source/manifest.json uses literal newlines inside the quoted description string,
making the manifest invalid JSON so Chrome will reject the extension at load time.
Code

extension/source/manifest.json[R8-27]

Evidence
The description field is a multi-line quoted string, which is invalid JSON and will cause Chrome's
manifest parser to error out.

extension/source/manifest.json[8-28]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`manifest.json` contains raw newlines inside the `description` string. JSON does not allow unescaped newline characters in strings, so the extension will fail to load.
### Issue Context
The `description` field spans multiple lines without using `\n` escape sequences.
### Fix Focus Areas
- extension/source/manifest.json[8-27]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Remote eval injection 🐞 Bug ⛨ Security
Description
inject.js fetches JavaScript from raw.githubusercontent.com and executes it via eval, enabling
arbitrary remote code execution on every matched Duolingo page.
Code

extension/source/inject.js[R278-285]

Evidence
inject.js downloads code from a remote URL and runs it via eval. The manifest shows this loader
runs on all https://*.duolingo.(com|cn)/* pages via a content script that injects inject.js into
the page.

extension/source/inject.js[276-288]
extension/source/manifest.json[33-46]
extension/source/content.js[1-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The extension downloads a remote userscript at runtime and executes it with `eval`. This enables remote code execution and will also violate common extension distribution policies (no remotely hosted code).
### Issue Context
The repository already contains the userscript (`v2/duohacker-v2.user.js`). The loader should inject a bundled, versioned copy instead of fetching arbitrary code at runtime.
### Fix Focus Areas
- extension/source/inject.js[276-288]
- extension/source/manifest.json[33-46]
- v2/duohacker-v2.user.js[1-40]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. CORS bypass not implemented 🐞 Bug ☼ Reliability
Description
The GM_xmlhttpRequest shim is implemented using page-context fetch, which cannot provide the
CORS-bypass behavior the userscript explicitly depends on; cross-origin API calls (e.g.,
https://api.twisk.fun/support) will not behave like Tampermonkey and will break features.
Code

extension/source/inject.js[R47-66]

Evidence
The harness implements GM_xmlhttpRequest with fetch(). The userscript explicitly states it uses
GM_xmlhttpRequest so CORS is bypassed and also performs cross-origin calls to api.twisk.fun,
which will not receive Tampermonkey-like CORS bypass in the current implementation.

extension/source/inject.js[47-66]
v2/duohacker-v2.user.js[4027-4046]
v2/duohacker-v2.user.js[3970-3972]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The userscript relies on Tampermonkey's `GM_xmlhttpRequest` specifically to bypass CORS. The current harness implements it with `fetch()` from a page-injected script, so requests are still subject to normal browser CORS/CSP rules.
### Issue Context
The userscript makes cross-origin calls (e.g., support chat to `https://api.twisk.fun/support`) and documents that it expects CORS bypass via `GM_xmlhttpRequest`.
### Fix Focus Areas
- extension/source/inject.js[47-66]
- extension/source/content.js[1-9]
- v2/duohacker-v2.user.js[3970-3972]
- v2/duohacker-v2.user.js[4027-4046]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Stray temp file ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
extension/temp is an empty file added to the repo and is not referenced by the extension; it adds
noise and is likely accidental.
Code

extension/temp[1]

+
Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An empty `extension/temp` file was added but is not used by the extension.
### Issue Context
Keeping unused artifacts makes the repo harder to maintain and review.
### Fix Focus Areas
- extension/temp[1-1]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread extension/source/manifest.json Outdated
Comment thread extension/source/inject.js
Comment thread extension/source/inject.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant