├── .github ├── FUNDING.yml └── icon.png ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── UImodul.js ├── captchaSolver.js ├── captchaSolverApi.js ├── config.js ├── index.js └── utils.js └── webpack.config.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: red_official 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: #['https://www.paypal.com/donate/?hosted_button_id=LTL43KCDUWVPL'] 14 | -------------------------------------------------------------------------------- /.github/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LetsUpdate/CSN/769994b8e7f283559937b0663ebef15e60bce4d9/.github/icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | 7 | # Logs 8 | logs/ 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | lerna-debug.log* 14 | 15 | # Dependency directories 16 | node_modules/ 17 | jspm_packages/ 18 | 19 | # Optional npm cache directory 20 | .npm 21 | 22 | # Optional eslint cache 23 | .eslintcache 24 | 25 | # Optional REPL history 26 | .node_repl_history 27 | 28 | # Output of 'npm pack' 29 | *.tgz 30 | 31 | # Coverage directory used by tools like istanbul 32 | coverage/ 33 | 34 | # Webpack files 35 | dist/ 36 | build/ 37 | 38 | # IDE specific files 39 | .vscode/ 40 | .idea/ 41 | 42 | # MacOS specific files 43 | .DS_Store 44 | 45 | # Environment variables 46 | .env 47 | .env.local 48 | .env.development.local 49 | .env.test.local 50 | .env.production.local 51 | 52 | # Tampermonkey specific files 53 | *.user.js 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 RED 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Captcha Solver for Neptun 2 | 3 | 4 | 5 | A **CSN** célja a Captcha kihívások megoldásának automatizálása a Neptun platformon. 6 | 7 | ## Újdonság: a script fixelve, és teljesen újra lett gondolva! 8 | 9 | 10 | 11 | *Dobj egy csillagot hogy tudjak vele menőzni!* [⭐KaptamEgyCsillagot!!!⭐](https://coub.com/view/1uvg42) 12 | 13 | Telepítési útmutató: 14 | 1. Első lépésként telepítsd a böngésződbe a [Tampermonkey](https://www.tampermonkey.net/) kiegészítőt, amely lehetővé teszi a JavaScript alapú szkriptek futtatását a böngésződben. 15 | 2. A szkript telepítéséhez [kattints ide](https://github.com/LetsUpdate/CSN/releases/latest/download/CSN.user.js). Ezután a szkript automatikusan bekerül a Tampermonkey kiegészítőbe, és már el is kezdheted használni! 16 | 3. **Az első használatkor engedélyt fog kérni a backend szerverre való csatlakozáshoz, engedélyezd ezt neki.** 17 | 18 | **Figyelem:** A script csak a captcha-t küldi el és a szerver is csak azt képes elfogadni. Ha nem hiszed, nézd meg a kódot! 19 | 20 | *tipp: Ha nem működne a PowerUp [@boglarka](https://github.com/boglarkla) írt rá egy fixet: [boglarka/npufix](https://github.com/boglarkla/npu/)* 21 | 22 | 23 | 24 | ## 25 | *Ha nagyon tetszett, akár [meghívhatsz egy kávéra](https://ko-fi.com/red_official)* 26 | 27 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Q5Q0O1LDA) 28 | 29 | koszi :P 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "csn2", 3 | "version": "1.0.3", 4 | "description": "Captcha Solver For Neptun", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "build:prod": "webpack", 8 | "build:dev": "cross-env NODE_ENV=development webpack", 9 | "watch": "cross-env NODE_ENV=development webpack --watch", 10 | "serve": "cross-env NODE_ENV=development webpack serve --mode development" 11 | }, 12 | "author": "RED", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "cross-env": "^7.0.3", 16 | "eslint": "^8.36.0", 17 | "eslint-config-prettier": "^8.7.0", 18 | "npm-run-all": "^4.1.5", 19 | "prettier": "^2.8.4", 20 | "terser-webpack-plugin": "^5.3.10", 21 | "webpack": "^5.93.0", 22 | "webpack-cli": "^5.1.4", 23 | "webpack-dev-server": "^5.0.4", 24 | "webpack-userscript": "^3.2.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/UImodul.js: -------------------------------------------------------------------------------- 1 | const icons = { 2 | "logo": "https://raw.githubusercontent.com/LetsUpdate/CSN/main/.github/icon.png", 3 | "networkError": "data:image/png;base64,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", 4 | "scriptError": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAABNUlEQVR4nO2XUY6DMAxE0+1Z+pfrcAb641X2BFzK6YlKTrGqV/0r0ao0KgqUvJHmC4Xg0YxtnAOgCi4x/kbV26s0s4PbE6Lq7RKjvcphGL7cnhARQPflgCC9PTKqPmVe4H/nH5/Pve/n+zw5X12wMFPAHPMCSs/n9yPA0LgDuq47Vi04jeOEJR+/BMfrdXJ//n0IsDQCDuiJQHjSA+6857IW87tX7wFpZSKA4AAjAkIPMJqgMAVsE2NQT37C0rFWen5zU0ARwOMAbTkCqbCgdyODAIIDjAjIhntAWjjzH9cDEgKMOCC1HAFlD/AsQsom6NtZhZW/Qd/236AigG/bAakyEUBwgBEBoQcYTVCYAsYYFPYAYxFaGoFNsG97Fc6RX7g2XW2EDRSNAIIDbLUIAAAAcJ+PP+cSOT5diQGeAAAAAElFTkSuQmCC", 5 | } 6 | 7 | const id = "CSN_LOGO" 8 | 9 | function getCaptchaWindow() { 10 | return $('#step2Captcha > div:nth-child(1)') 11 | } 12 | 13 | 14 | function PlaceLogo() { 15 | const style = document.createElement('style'); 16 | style.type = 'text/css'; 17 | style.innerHTML = ` 18 | @keyframes spin { 19 | from { transform: rotate(0deg); } 20 | to { transform: rotate(360deg); } 21 | } 22 | `; 23 | document.getElementsByTagName('head')[0].appendChild(style); 24 | 25 | getCaptchaWindow().append( 26 | `
27 | logo 28 |
` 29 | ) 30 | //onclick event open https://github.com/LetsUpdate/CSN 31 | $(`#${id}`).click(() => { 32 | window.open('https://github.com/LetsUpdate/CSN', '_blank'); 33 | }); 34 | 35 | } 36 | 37 | const LogoState = { 38 | "default": "default", 39 | "solving": "solving", 40 | "error":"error", 41 | "networkError":"networkError", 42 | } 43 | 44 | function SetState(state){ 45 | const logo = $(`#${id} > img`) 46 | switch(state){ 47 | case LogoState.default: 48 | logo.attr('src', icons.logo) 49 | logo.css('animation', 'none') 50 | break; 51 | case LogoState.solving: 52 | logo.attr('src', icons.logo) 53 | logo.attr('title', 'Megoldás folyamatban...') 54 | //rotate the logo 55 | logo.css({ 56 | 'animation': 'spin 0.8s linear infinite', 57 | '-webkit-animation': 'spin 0.8s linear infinite', // For Safari 58 | '-moz-animation': 'spin 0.8s linear infinite', // For Firefox 59 | '-o-animation': 'spin 0.8s linear infinite' // For Opera 60 | }); 61 | break; 62 | case LogoState.error: 63 | logo.attr('src', icons.scriptError) 64 | logo.css('animation', 'none') 65 | //add hint 66 | logo.attr('title', 'Ismeretlen hiba a captcha megoldása közben') 67 | break; 68 | case LogoState.networkError: 69 | logo.attr('src', icons.networkError) 70 | logo.css('animation', 'none') 71 | logo.attr('title', 'CSN Szerver Hiba / unreachable') 72 | break; 73 | } 74 | } 75 | 76 | 77 | module.exports = { PlaceLogo, SetState, LogoState } -------------------------------------------------------------------------------- /src/captchaSolver.js: -------------------------------------------------------------------------------- 1 | const { solveCaptcha } = require('./captchaSolverApi'); 2 | const { SetState, LogoState } = require('./UImodul'); 3 | 4 | const $ = window.jQuery; 5 | 6 | //refreshIcon 7 | function getCaptchaRefreshIcon() { 8 | return $(".captchaRefreshIcon"); 9 | } 10 | //captchaImage 11 | function getCaptchaImage() { 12 | return $("#upCaptchaLogin_loginCaptcha > img"); 13 | } 14 | // 15 | function getCaptchaInput() { 16 | return $("#txtCaptchaLogin"); 17 | } 18 | // 19 | //body > div.ui-dialog.ui-widget.ui-widget-content.ui-corner-all.ui-front.ui-dialog-buttons.ui-draggable > div.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix > div > button:nth-child(2) 20 | function getNewLoginButton() { 21 | // Use a more specific selector to target buttons with text containing 'Belépés' or 'login' (case-insensitive) 22 | return $("button.ui-button").filter(function () { 23 | return /belépés|login/i.test($(this).text()); 24 | }); 25 | } 26 | // 27 | function getFirstLogin() { 28 | return $("#btnSubmit"); 29 | } 30 | 31 | function getErrorLabel() { 32 | return $("#txtCaptchaLogin-error"); 33 | } 34 | 35 | function scanForElementText(element, timeout = 10000) { 36 | return new Promise((resolve, reject) => { 37 | const intervalTime = 100; // Interval time in milliseconds 38 | let elapsedTime = 0; 39 | 40 | const interval = setInterval(() => { 41 | if (element === null) { return; } 42 | if (element.text().trim().length > 0) { 43 | clearInterval(interval); 44 | resolve(false); // Captcha is invalid 45 | } 46 | 47 | elapsedTime += intervalTime; 48 | if (elapsedTime >= timeout) { 49 | clearInterval(interval); 50 | reject("TIME_OUT"); // Captcha is valid (no error message appeared within the timeout) 51 | } 52 | }, intervalTime); 53 | }); 54 | } 55 | let tryes = 0; 56 | async function StartSolving(imgsrc) { 57 | 58 | if (tryes > 4) { 59 | SetState(LogoState.error); 60 | return; 61 | } 62 | SetState(LogoState.solving); 63 | tryes++; 64 | 65 | 66 | const captchaImage = getCaptchaImage(); 67 | const loginButton = getNewLoginButton(); 68 | const captchaInput = getCaptchaInput() 69 | const captchaRefreshIcon = getCaptchaRefreshIcon(); 70 | 71 | try { 72 | console.log('Solving captcha...'); 73 | await new Promise((resolve) => setTimeout(resolve, 100)); 74 | let captchaSolution; 75 | if (imgsrc === captchaImage[0].src) { 76 | captchaSolution = await solveCaptcha(captchaImage[0]); 77 | } else { 78 | console.log('Captcha image changed, terminating...'); 79 | return; 80 | } 81 | 82 | 83 | captchaInput.val(captchaSolution); 84 | 85 | if (imgsrc === captchaImage[0].src) { 86 | await new Promise((resolve) => setTimeout(resolve, 100)); 87 | loginButton.click(); 88 | console.log('Captcha solved:', captchaSolution); 89 | } else { 90 | console.log('Captcha image changed, terminating...'); 91 | return; 92 | } 93 | 94 | // Ne spammeljük a szervert szét 95 | await new Promise((resolve) => setTimeout(resolve, 500)); 96 | 97 | 98 | //Mutotion observer observe the error label 99 | //if the captcha is invalid the error label will not be empty 100 | 101 | 102 | //wait for the error label to appear 103 | console.log('Waiting for error label...'); 104 | try { 105 | await scanForElementText(getErrorLabel()); 106 | console.log('Captcha is invalid:', getErrorLabel().text()); 107 | getErrorLabel().text(""); 108 | console.log('waitforCaptchaRefresh'); 109 | captchaRefreshIcon.click(); 110 | return; 111 | } 112 | catch (error) { 113 | if (error === "TIME_OUT") { 114 | console.log('TimedOut'); 115 | } else { 116 | console.error('Failed to solve captcha:', error); 117 | } 118 | return; 119 | } 120 | 121 | } 122 | catch (error) { 123 | 124 | if (error === "HARD_IMAGE") { 125 | captchaRefreshIcon.click(); 126 | 127 | } else { 128 | 129 | console.error('Failed to solve captcha:', error); 130 | SetState(LogoState.networkError); 131 | return; 132 | } 133 | } 134 | } 135 | 136 | 137 | 138 | 139 | function handleImageLoad() { 140 | console.log('Image loaded:', getCaptchaImage()[0].src); 141 | StartSolving(getCaptchaImage()[0].src); 142 | } 143 | 144 | 145 | 146 | function LookForCaptcha() { 147 | 148 | const $imgElement = getCaptchaImage(); 149 | const imgElement = $imgElement[0]; 150 | 151 | //onbutton click reset tryes 152 | getFirstLogin().click(function () { 153 | tryes = 0; 154 | }); 155 | 156 | // Check if the element exists 157 | if (imgElement) { 158 | // Create a new MutationObserver 159 | const observer = new MutationObserver((mutations) => { 160 | mutations.forEach((mutation) => { 161 | if (mutation.type === 'attributes' && mutation.attributeName === 'src') { 162 | console.log('Image src changed to:', imgElement.src); 163 | 164 | 165 | // Attach a load event listener to ensure the image is loaded 166 | $imgElement.off('load').on('load', function () { 167 | if (this.complete && this.naturalWidth > 0) { 168 | handleImageLoad(); 169 | } 170 | }); 171 | 172 | // Also handle the case where the image might already be cached 173 | // if (imgElement.complete && imgElement.naturalWidth > 0) { 174 | // console.log('Image loaded from cache:', imgElement.src); 175 | // handleImageLoad(); 176 | // } 177 | 178 | 179 | } 180 | }); 181 | }); 182 | 183 | // Start observing the image element for changes in its attributes 184 | observer.observe(imgElement, { 185 | attributes: true // Listen for attribute changes 186 | }); 187 | } else { 188 | console.error('Image element not found'); 189 | } 190 | 191 | console.log('Observing document body for changes...'); 192 | } 193 | 194 | 195 | 196 | module.exports = { LookForCaptcha }; -------------------------------------------------------------------------------- /src/captchaSolverApi.js: -------------------------------------------------------------------------------- 1 | const config = require('./config'); 2 | 3 | function convertImageToBase64(imageElement) { 4 | // Create a canvas element 5 | const canvas = document.createElement('canvas'); 6 | const context = canvas.getContext('2d'); 7 | 8 | // Set canvas dimensions to match the image 9 | canvas.width = imageElement.naturalWidth; 10 | canvas.height = imageElement.naturalHeight; 11 | 12 | // Draw the image onto the canvas 13 | context.drawImage(imageElement, 0, 0); 14 | 15 | // Convert the canvas content to a Data URL (Base64 string) 16 | const base64String = canvas.toDataURL('image/jpeg'); 17 | 18 | // Resolve the promise with the Base64 string 19 | return base64String; 20 | 21 | } 22 | 23 | // if return message is "HARD_IMAGE" then the image is too hard to solve rigt now 24 | function solveCaptcha(imageElement) { 25 | return new Promise((resolve, reject) => { 26 | // Convert the canvas content to a Data URL (Base64 string) 27 | const base64String = convertImageToBase64(imageElement); 28 | 29 | if(base64String.length < 100) { 30 | reject('BASE64_CONVERSION_FAILED'); 31 | return; 32 | } 33 | 34 | // Make the GM_xmlhttpRequest with the Base64 string 35 | GM_xmlhttpRequest({ 36 | method: 'POST', 37 | url: config.API_URL, // Replace with your API endpoint 38 | headers: { 39 | 'Content-Type': 'application/json' 40 | }, 41 | data: JSON.stringify({ image64: base64String }), 42 | onload: function(response) { 43 | if (response.status === 200) { 44 | try { 45 | const jsonResponse = JSON.parse(response.responseText); 46 | if(jsonResponse.message === "HARD_IMAGE") { 47 | reject(jsonResponse.message); 48 | 49 | }else{ resolve(jsonResponse.message);} 50 | 51 | 52 | } catch (error) { 53 | reject(new Error('Failed to parse response JSON')); 54 | } 55 | } else { 56 | console.error('Failed to solve captcha:', JSON.parse(response.responseText).error); 57 | reject(new Error('Failed to solve captcha')); 58 | } 59 | }, 60 | onerror: function(error) { 61 | reject(error); 62 | } 63 | }); 64 | }); 65 | } 66 | 67 | 68 | 69 | // Export the function for use in other modules 70 | module.exports = { solveCaptcha, convertImageToBase64 }; -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | API_URL: 'https://csn.redsparks.eu/api/v1/solve', 3 | } 4 | //config.API_URL = 'http://localhost:8000/api/v1/solve'; 5 | module.exports = config; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const utils = require("./utils"); 2 | const { LookForCaptcha } = require('./captchaSolver'); 3 | const {PlaceLogo} = require('./UImodul'); 4 | 5 | 6 | 7 | (function () { 8 | 'use strict'; 9 | 10 | if (utils.isNeptunPage() && utils.isLoginPage()) { 11 | // Set up a Mutation Observer to watch for changes in the DOM 12 | 13 | //Prevent npu to press login after the user too 14 | document.addEventListener('keydown', function(event) { 15 | if (event.key === 'Enter') { 16 | const $abortLoginLink = $('#abortLogin > a'); 17 | if ($abortLoginLink.length) { 18 | $abortLoginLink[0].click(); 19 | } 20 | } 21 | }); 22 | console.log("LookForCaptcha"); 23 | PlaceLogo(); 24 | LookForCaptcha(); 25 | } 26 | })(); -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const $ = window.jQuery; 2 | 3 | // Verify that we are indeed on a Neptun page 4 | function isNeptunPage() { 5 | return document.title.toLowerCase().indexOf("neptun.net") !== -1; 6 | } 7 | 8 | // Returns whether we are on the login page 9 | function isLoginPage() { 10 | return $("td.login_left_side").size() > 0; 11 | } 12 | 13 | module.exports = { 14 | isNeptunPage, 15 | isLoginPage, 16 | }; 17 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const { UserscriptPlugin } = require('webpack-userscript'); 3 | const TerserPlugin = require('terser-webpack-plugin'); 4 | 5 | 6 | const dev = process.env.NODE_ENV === 'development'; 7 | 8 | module.exports = { 9 | mode: dev ? 'development' : 'production', 10 | entry: path.resolve(__dirname, 'src', 'index.js'), // Your entry point 11 | output: { 12 | path: path.resolve(__dirname, 'dist'), 13 | filename: 'CSN.user.js', // Output file 14 | }, 15 | devServer: { 16 | static: { 17 | directory: path.join(__dirname, 'dist'), 18 | }, 19 | client: false, // Disable client injection 20 | hot: false, // Disable hot reloading 21 | 22 | 23 | }, 24 | optimization: { 25 | minimize: dev ? false : true, 26 | minimizer: [ 27 | new TerserPlugin({ 28 | terserOptions: { 29 | compress: { 30 | drop_console: dev ? false : true, 31 | }, 32 | }, 33 | }), 34 | ], 35 | }, 36 | plugins: [ 37 | new UserscriptPlugin({ 38 | headers(original) { 39 | const baseHeaders = { 40 | name: 'Captcha Solver For Neptun', 41 | namespace: 'https://github.com/LetsUpdate/CSN', 42 | description: 'No captcha 4 u', 43 | author: 'RED', 44 | include: [ 45 | 'https://*neptun*/*hallgato*/*', 46 | 'https://*neptun*/*Hallgatoi*/*', 47 | 'https://*hallgato*.*neptun*/*', 48 | 'https://netw*.nnet.sze.hu/hallgato', 49 | 'https://nappw.dfad.duf.hu/hallgato/*', 50 | ], 51 | grant: 'GM_xmlhttpRequest', 52 | "run-at": "document-end", 53 | require: "https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js", 54 | updateURL: "https://github.com/LetsUpdate/CSN/releases/latest/download/CSN.meta.js", 55 | downloadURL:"https://github.com/LetsUpdate/CSN/releases/latest/download/CSN.user.js", 56 | supportURL:"https://github.com/LetsUpdate/CSN", 57 | icon64: "https://raw.githubusercontent.com/LetsUpdate/CSN/main/.github/icon.png", 58 | license: "MIT", 59 | 60 | }; 61 | 62 | if (dev) { 63 | return { 64 | ...original, 65 | ...baseHeaders, 66 | version: `${original.version}-build.[buildNo]`, 67 | }; 68 | } 69 | 70 | return { 71 | ...original, 72 | ...baseHeaders, 73 | }; 74 | }, 75 | 76 | }), 77 | 78 | ], 79 | }; --------------------------------------------------------------------------------