├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── scripts └── itemAdder.js └── src ├── config.js ├── enums └── actionType.js ├── events ├── buddyEvents.js ├── engineEvents.js ├── gameEvents.js ├── ignoreEvents.js ├── inventoryEvents.js ├── loginEvents.js ├── navigationEvents.js ├── playerEvents.js └── worldEvents.js ├── index.js ├── networking ├── connection.js └── penguin.js └── utils ├── cryptoUtils.js └── logger.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # Snowpack dependency directory (https://snowpack.dev/) 45 | web_modules/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | .parcel-cache 78 | 79 | # Next.js build output 80 | .next 81 | out 82 | 83 | # Nuxt.js build / generate output 84 | .nuxt 85 | dist 86 | 87 | # Gatsby files 88 | .cache/ 89 | # Comment in the public line in if your project uses Gatsby and not Next.js 90 | # https://nextjs.org/blog/next-9-1#public-directory-support 91 | # public 92 | 93 | # vuepress build output 94 | .vuepress/dist 95 | 96 | # Serverless directories 97 | .serverless/ 98 | 99 | # FuseBox cache 100 | .fusebox/ 101 | 102 | # DynamoDB Local files 103 | .dynamodb/ 104 | 105 | # TernJS port file 106 | .tern-port 107 | 108 | # Stores VSCode versions used for testing VSCode extensions 109 | .vscode-test 110 | 111 | # yarn v2 112 | .yarn/cache 113 | .yarn/unplugged 114 | .yarn/build-state.yml 115 | .yarn/install-state.gz 116 | .pnp.* 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CPR Client Library 2 | Client library for Club Penguin Rewritten's HTML5 client. 3 | 4 | ## Installation 5 | Make sure you have the latest LTS version of Node.js installed on your operating system. Edit `src/config.js` with the appropriate configuration options under the `scripts` portion of the file. Then, run the sample program: 6 | ``` 7 | $ git clone https://github.com/LegitCP/cpr-client-library 8 | $ cd cpr-client-library 9 | $ npm install 10 | $ node src/index.js 11 | ``` 12 | 13 | ## Documentation 14 | Coming soon! View the scripts inside the `scripts` folder for various examples of how to work with the library for now. 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cpr-client-library", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@dabh/diagnostics": { 8 | "version": "2.0.2", 9 | "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", 10 | "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==", 11 | "requires": { 12 | "colorspace": "1.1.x", 13 | "enabled": "2.0.x", 14 | "kuler": "^2.0.0" 15 | } 16 | }, 17 | "after": { 18 | "version": "0.8.2", 19 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", 20 | "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" 21 | }, 22 | "arraybuffer.slice": { 23 | "version": "0.0.7", 24 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", 25 | "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" 26 | }, 27 | "async": { 28 | "version": "3.2.0", 29 | "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", 30 | "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" 31 | }, 32 | "async-limiter": { 33 | "version": "1.0.1", 34 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", 35 | "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" 36 | }, 37 | "backo2": { 38 | "version": "1.0.2", 39 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 40 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 41 | }, 42 | "base64-arraybuffer": { 43 | "version": "0.1.5", 44 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 45 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 46 | }, 47 | "better-assert": { 48 | "version": "1.0.2", 49 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 50 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 51 | "requires": { 52 | "callsite": "1.0.0" 53 | } 54 | }, 55 | "blob": { 56 | "version": "0.0.5", 57 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", 58 | "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" 59 | }, 60 | "callsite": { 61 | "version": "1.0.0", 62 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 63 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 64 | }, 65 | "color": { 66 | "version": "3.0.0", 67 | "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", 68 | "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", 69 | "requires": { 70 | "color-convert": "^1.9.1", 71 | "color-string": "^1.5.2" 72 | } 73 | }, 74 | "color-convert": { 75 | "version": "1.9.3", 76 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 77 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 78 | "requires": { 79 | "color-name": "1.1.3" 80 | } 81 | }, 82 | "color-name": { 83 | "version": "1.1.3", 84 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 85 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 86 | }, 87 | "color-string": { 88 | "version": "1.5.3", 89 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", 90 | "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", 91 | "requires": { 92 | "color-name": "^1.0.0", 93 | "simple-swizzle": "^0.2.2" 94 | } 95 | }, 96 | "colors": { 97 | "version": "1.4.0", 98 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 99 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" 100 | }, 101 | "colorspace": { 102 | "version": "1.1.2", 103 | "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", 104 | "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", 105 | "requires": { 106 | "color": "3.0.x", 107 | "text-hex": "1.0.x" 108 | } 109 | }, 110 | "component-bind": { 111 | "version": "1.0.0", 112 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 113 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 114 | }, 115 | "component-emitter": { 116 | "version": "1.3.0", 117 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 118 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" 119 | }, 120 | "component-inherit": { 121 | "version": "0.0.3", 122 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 123 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 124 | }, 125 | "core-util-is": { 126 | "version": "1.0.2", 127 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 128 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 129 | }, 130 | "debug": { 131 | "version": "4.1.1", 132 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 133 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 134 | "requires": { 135 | "ms": "^2.1.1" 136 | } 137 | }, 138 | "enabled": { 139 | "version": "2.0.0", 140 | "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", 141 | "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" 142 | }, 143 | "engine.io-client": { 144 | "version": "3.4.3", 145 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz", 146 | "integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==", 147 | "requires": { 148 | "component-emitter": "~1.3.0", 149 | "component-inherit": "0.0.3", 150 | "debug": "~4.1.0", 151 | "engine.io-parser": "~2.2.0", 152 | "has-cors": "1.1.0", 153 | "indexof": "0.0.1", 154 | "parseqs": "0.0.5", 155 | "parseuri": "0.0.5", 156 | "ws": "~6.1.0", 157 | "xmlhttprequest-ssl": "~1.5.4", 158 | "yeast": "0.1.2" 159 | }, 160 | "dependencies": { 161 | "component-emitter": { 162 | "version": "1.3.0", 163 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 164 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" 165 | } 166 | } 167 | }, 168 | "engine.io-parser": { 169 | "version": "2.2.0", 170 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", 171 | "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", 172 | "requires": { 173 | "after": "0.8.2", 174 | "arraybuffer.slice": "~0.0.7", 175 | "base64-arraybuffer": "0.1.5", 176 | "blob": "0.0.5", 177 | "has-binary2": "~1.0.2" 178 | } 179 | }, 180 | "fast-safe-stringify": { 181 | "version": "2.0.7", 182 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", 183 | "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" 184 | }, 185 | "fecha": { 186 | "version": "4.2.0", 187 | "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", 188 | "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" 189 | }, 190 | "file-stream-rotator": { 191 | "version": "0.5.7", 192 | "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.5.7.tgz", 193 | "integrity": "sha512-VYb3HZ/GiAGUCrfeakO8Mp54YGswNUHvL7P09WQcXAJNSj3iQ5QraYSp3cIn1MUyw6uzfgN/EFOarCNa4JvUHQ==", 194 | "requires": { 195 | "moment": "^2.11.2" 196 | } 197 | }, 198 | "fn.name": { 199 | "version": "1.1.0", 200 | "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", 201 | "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" 202 | }, 203 | "has-binary2": { 204 | "version": "1.0.3", 205 | "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", 206 | "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", 207 | "requires": { 208 | "isarray": "2.0.1" 209 | } 210 | }, 211 | "has-cors": { 212 | "version": "1.1.0", 213 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 214 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 215 | }, 216 | "indexof": { 217 | "version": "0.0.1", 218 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 219 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 220 | }, 221 | "inherits": { 222 | "version": "2.0.4", 223 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 224 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 225 | }, 226 | "is-arrayish": { 227 | "version": "0.3.2", 228 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", 229 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" 230 | }, 231 | "is-stream": { 232 | "version": "2.0.0", 233 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 234 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" 235 | }, 236 | "isarray": { 237 | "version": "2.0.1", 238 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", 239 | "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" 240 | }, 241 | "kuler": { 242 | "version": "2.0.0", 243 | "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", 244 | "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" 245 | }, 246 | "logform": { 247 | "version": "2.2.0", 248 | "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", 249 | "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", 250 | "requires": { 251 | "colors": "^1.2.1", 252 | "fast-safe-stringify": "^2.0.4", 253 | "fecha": "^4.2.0", 254 | "ms": "^2.1.1", 255 | "triple-beam": "^1.3.0" 256 | } 257 | }, 258 | "moment": { 259 | "version": "2.27.0", 260 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", 261 | "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" 262 | }, 263 | "ms": { 264 | "version": "2.1.2", 265 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 266 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 267 | }, 268 | "object-component": { 269 | "version": "0.0.3", 270 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 271 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 272 | }, 273 | "object-hash": { 274 | "version": "2.0.3", 275 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", 276 | "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==" 277 | }, 278 | "one-time": { 279 | "version": "1.0.0", 280 | "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", 281 | "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", 282 | "requires": { 283 | "fn.name": "1.x.x" 284 | } 285 | }, 286 | "parseqs": { 287 | "version": "0.0.5", 288 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 289 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 290 | "requires": { 291 | "better-assert": "~1.0.0" 292 | } 293 | }, 294 | "parseuri": { 295 | "version": "0.0.5", 296 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 297 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 298 | "requires": { 299 | "better-assert": "~1.0.0" 300 | } 301 | }, 302 | "process-nextick-args": { 303 | "version": "2.0.1", 304 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 305 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 306 | }, 307 | "readable-stream": { 308 | "version": "3.6.0", 309 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 310 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 311 | "requires": { 312 | "inherits": "^2.0.3", 313 | "string_decoder": "^1.1.1", 314 | "util-deprecate": "^1.0.1" 315 | } 316 | }, 317 | "safe-buffer": { 318 | "version": "5.2.1", 319 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 320 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 321 | }, 322 | "simple-swizzle": { 323 | "version": "0.2.2", 324 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", 325 | "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", 326 | "requires": { 327 | "is-arrayish": "^0.3.1" 328 | } 329 | }, 330 | "socket.io-client": { 331 | "version": "2.3.0", 332 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", 333 | "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", 334 | "requires": { 335 | "backo2": "1.0.2", 336 | "base64-arraybuffer": "0.1.5", 337 | "component-bind": "1.0.0", 338 | "component-emitter": "1.2.1", 339 | "debug": "~4.1.0", 340 | "engine.io-client": "~3.4.0", 341 | "has-binary2": "~1.0.2", 342 | "has-cors": "1.1.0", 343 | "indexof": "0.0.1", 344 | "object-component": "0.0.3", 345 | "parseqs": "0.0.5", 346 | "parseuri": "0.0.5", 347 | "socket.io-parser": "~3.3.0", 348 | "to-array": "0.1.4" 349 | }, 350 | "dependencies": { 351 | "component-emitter": { 352 | "version": "1.2.1", 353 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 354 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 355 | } 356 | } 357 | }, 358 | "socket.io-parser": { 359 | "version": "3.3.0", 360 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", 361 | "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", 362 | "requires": { 363 | "component-emitter": "1.2.1", 364 | "debug": "~3.1.0", 365 | "isarray": "2.0.1" 366 | }, 367 | "dependencies": { 368 | "component-emitter": { 369 | "version": "1.2.1", 370 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 371 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 372 | }, 373 | "debug": { 374 | "version": "3.1.0", 375 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 376 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 377 | "requires": { 378 | "ms": "2.0.0" 379 | } 380 | }, 381 | "ms": { 382 | "version": "2.0.0", 383 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 384 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 385 | } 386 | } 387 | }, 388 | "stack-trace": { 389 | "version": "0.0.10", 390 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 391 | "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" 392 | }, 393 | "string_decoder": { 394 | "version": "1.3.0", 395 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 396 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 397 | "requires": { 398 | "safe-buffer": "~5.2.0" 399 | } 400 | }, 401 | "text-hex": { 402 | "version": "1.0.0", 403 | "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", 404 | "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" 405 | }, 406 | "to-array": { 407 | "version": "0.1.4", 408 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 409 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 410 | }, 411 | "triple-beam": { 412 | "version": "1.3.0", 413 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", 414 | "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" 415 | }, 416 | "util-deprecate": { 417 | "version": "1.0.2", 418 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 419 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 420 | }, 421 | "winston": { 422 | "version": "3.3.3", 423 | "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", 424 | "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", 425 | "requires": { 426 | "@dabh/diagnostics": "^2.0.2", 427 | "async": "^3.1.0", 428 | "is-stream": "^2.0.0", 429 | "logform": "^2.2.0", 430 | "one-time": "^1.0.0", 431 | "readable-stream": "^3.4.0", 432 | "stack-trace": "0.0.x", 433 | "triple-beam": "^1.3.0", 434 | "winston-transport": "^4.4.0" 435 | } 436 | }, 437 | "winston-daily-rotate-file": { 438 | "version": "4.5.0", 439 | "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.0.tgz", 440 | "integrity": "sha512-/HqeWiU48dzGqcrABRlxYWVMdL6l3uKCtFSJyrqK+E2rLnSFNsgYpvwx15EgTitBLNzH69lQd/+z2ASryV2aqw==", 441 | "requires": { 442 | "file-stream-rotator": "^0.5.7", 443 | "object-hash": "^2.0.1", 444 | "triple-beam": "^1.3.0", 445 | "winston-transport": "^4.2.0" 446 | } 447 | }, 448 | "winston-transport": { 449 | "version": "4.4.0", 450 | "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", 451 | "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", 452 | "requires": { 453 | "readable-stream": "^2.3.7", 454 | "triple-beam": "^1.2.0" 455 | }, 456 | "dependencies": { 457 | "isarray": { 458 | "version": "1.0.0", 459 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 460 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 461 | }, 462 | "readable-stream": { 463 | "version": "2.3.7", 464 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 465 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 466 | "requires": { 467 | "core-util-is": "~1.0.0", 468 | "inherits": "~2.0.3", 469 | "isarray": "~1.0.0", 470 | "process-nextick-args": "~2.0.0", 471 | "safe-buffer": "~5.1.1", 472 | "string_decoder": "~1.1.1", 473 | "util-deprecate": "~1.0.1" 474 | } 475 | }, 476 | "safe-buffer": { 477 | "version": "5.1.2", 478 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 479 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 480 | }, 481 | "string_decoder": { 482 | "version": "1.1.1", 483 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 484 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 485 | "requires": { 486 | "safe-buffer": "~5.1.0" 487 | } 488 | } 489 | } 490 | }, 491 | "ws": { 492 | "version": "6.1.4", 493 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", 494 | "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", 495 | "requires": { 496 | "async-limiter": "~1.0.0" 497 | } 498 | }, 499 | "xmlhttprequest-ssl": { 500 | "version": "1.5.5", 501 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", 502 | "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" 503 | }, 504 | "yeast": { 505 | "version": "0.1.2", 506 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 507 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 508 | } 509 | } 510 | } 511 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cpr-client-library", 3 | "version": "1.0.0", 4 | "description": "Client library for Club Penguin Rewritten's new HTML5 client.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Legit", 10 | "license": "MIT", 11 | "dependencies": { 12 | "component-emitter": "^1.3.0", 13 | "socket.io-client": "^2.3.0", 14 | "winston": "^3.3.3", 15 | "winston-daily-rotate-file": "^4.5.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/itemAdder.js: -------------------------------------------------------------------------------- 1 | const Penguin = require('../src/networking/penguin'); 2 | 3 | // Credits: https://github.com/wesbos/waait 4 | const wait = (amount = 0) => new Promise(resolve => setTimeout(resolve, amount)); 5 | 6 | const addItems = async (penguin, delay, freeOnly) => { 7 | logger.info('Adding items...'); 8 | 9 | const { item } = penguin.connection.crumbs; 10 | const items = freeOnly ? Object.entries(item).filter(([id, crumb]) => crumb.cost === 0) : Object.entries(item); 11 | 12 | for (const [id, crumb] of items) { 13 | logger.info(`Attempting to add item ${crumb.english} with cost of ${crumb.cost}...`); 14 | penguin.buyItem(parseInt(id)); 15 | await wait(delay); 16 | } 17 | 18 | logger.info(`Successfully added all ${freeOnly ? 'free' : ''} items to your CPR HTML5 account. Enjoy!`); 19 | process.exit(); 20 | }; 21 | 22 | exports.run = async (obj) => { 23 | logger.info('Initializing item adder...'); 24 | const myPenguin = new Penguin(obj.username, obj.password); 25 | await myPenguin.login({ server: 'blizzard' }); 26 | setupCallbacks(myPenguin, obj.delay); 27 | myPenguin.joinRoom(100, 490, 1020); 28 | }; 29 | 30 | const setupCallbacks = async (myPenguin, obj) => { 31 | myPenguin.connection.once(ActionType.NAVIGATION.JOIN_ROOM, async (packet) => { 32 | const { roomId, x, y } = packet; 33 | const room = myPenguin.connection.getCrumb('room'); 34 | 35 | logger.info(`Successfully joined room '${room[roomId].english}' at coords '${x}:${y}'`); 36 | 37 | logger.info('Starting item adder...'); 38 | await addItems(myPenguin, obj.delay, obj.freeOnly); 39 | }); 40 | 41 | myPenguin.connection.on(ActionType.INVENTORY.BUY_INVENTORY, (packet) => { 42 | const { itemId } = packet; 43 | const item = myPenguin.connection.getCrumb('item'); 44 | 45 | logger.info(`Successfully purchased item '${item[itemId].english}' with cost of ${item[itemId].cost}`); 46 | }); 47 | 48 | myPenguin.connection.on(ActionType.ENGINE.GET_PROMPT, (packet) => { 49 | const { message } = packet; 50 | 51 | logger.error(`An error occurred while attempting to purchase the previous item: ${message}`); 52 | }); 53 | }; 54 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | servers: { 5 | login: { 6 | ip: "https://server.cprewritten.net", 7 | port: 7070 8 | } 9 | }, 10 | scripts: { 11 | itemAdder: { 12 | /* 13 | August 6th, 2020: All items are available to be added. 14 | */ 15 | 16 | username: 'USERNAME_HERE', 17 | password: 'PASSWORD_HERE', 18 | 19 | /* 20 | Delay argument is in milliseconds, adjust for however long in between you want to add items! 21 | 1000 = 1 second between adding each item 22 | 23 | NOTE: It is highly recommended you don't run the scirpt too fast. It is likely in the future there will be a rate limit and server-side checks against adding patched items. 24 | */ 25 | delay: 1000, 26 | 27 | /* freeOnly -- Set to either 'true' or 'false' depending on if you want to add only free items or all items. */ 28 | freeOnly: true 29 | }, 30 | moneyMaker: { 31 | /* Money maker script not ready yet. Coming soon! */ 32 | }, 33 | }, 34 | debug: false 35 | } 36 | -------------------------------------------------------------------------------- /src/enums/actionType.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | USER: { 5 | LOGIN: 'login:u' 6 | }, 7 | WORLD: { 8 | AUTHENTICATE: 'world:auth' 9 | }, 10 | ENGINE: { 11 | GET_CRUMBS: 'engine:get_crumbs', 12 | GET_PLAYER: 'engine:get_player', 13 | PROMPT: 'engine:prompt' 14 | }, 15 | IGNORE: { 16 | GET_IGNORED: 'ignore:get_ignored' 17 | }, 18 | NAVIGATION: { 19 | ADD_PLAYER: 'navigation:add_player', 20 | GET_PLAYERS: 'navigation:get_players', 21 | JOIN_ROOM: 'navigation:join_room', 22 | REMOVE_PLAYER: 'navigation:remove_player' 23 | }, 24 | PLAYER: { 25 | ACTION: 'player:action', 26 | EMOTE: 'player:emote', 27 | MESSAGE: 'player:message', 28 | MOVE: 'player:move', 29 | UPDATE_WEARING: 'player:update_wearing' 30 | }, 31 | BUDDY: { 32 | ADD_BUDDY: 'buddy:add_buddy', 33 | FIND_BUDDY: 'buddy:find_buddy', 34 | GET_BUDDIES: 'buddy:get_buddies', 35 | NOTIFY_ONLINE: 'buddy:notify_online', 36 | NOTIFY_OFFLINE: 'buddy:notify_offline', 37 | REMOVE_BUDDY: 'buddy:remove_buddy', 38 | REQUEST_BUDDY: 'buddy:request_buddy', 39 | SEARCH: 'buddy:search' 40 | }, 41 | INVENTORY: { 42 | BUY_INVENTORY: 'inventory:buy_inventory', 43 | GET_INVENTORY: 'inventory:get_inventory' 44 | }, 45 | GAME: { 46 | OVER: 'game:over' 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /src/events/buddyEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleGetBuddies = (packet, connection) => { 4 | const buddyObj = { 5 | buddyList: packet.params[0] 6 | }; 7 | 8 | connection.emit(ActionType.BUDDY.GET_BUDDIES, buddyObj); 9 | }; 10 | 11 | exports.handleAddBuddy = (packet, connection) => { 12 | const buddyObj = { 13 | newBuddy: { 14 | id: parseInt(packet.params[0]), 15 | swid: packet.params[1], 16 | unapprovedName: packet.params[2], 17 | isMascot: packet.params[3] 18 | } 19 | }; 20 | 21 | connection.emit(ActionType.BUDDY.ADD_BUDDY, buddyObj); 22 | }; 23 | 24 | exports.handleRemoveBuddy = (packet, connection) => { 25 | const buddyObj = { 26 | removedBuddy: { 27 | id: parseInt(packet.params[0]) 28 | } 29 | }; 30 | 31 | connection.emit(ActionType.BUDDY.REMOVE_BUDDY, buddyObj); 32 | }; 33 | 34 | exports.handleRequestBuddy = (packet, connection) => { 35 | const buddyObj = { 36 | requestedBuddy: { 37 | id: parseInt(packet.params[0]), 38 | swid: packet.params[1], 39 | unapprovedName: packet.params[2] 40 | } 41 | }; 42 | 43 | connection.emit(ActionType.BUDDY.REQUEST_BUDDY, buddyObj); 44 | }; 45 | 46 | exports.handleFindBuddy = (packet, connection) => { 47 | const buddyObj = { 48 | foundBuddy: { 49 | unapprovedName: packet.params[0], 50 | roomName: packet.params[1] 51 | } 52 | }; 53 | 54 | connection.emit(ActionType.BUDDY.FIND_BUDDY, buddyObj); 55 | }; 56 | 57 | exports.handleNotifyOnline = (packet, connection) => { 58 | const buddyObj = { 59 | buddyId: parseInt(packet.params[0]) 60 | }; 61 | 62 | connection.emit(ActionType.BUDDY.NOTIFY_ONLINE, buddyObj); 63 | }; 64 | 65 | exports.handleNotifyOffline = (packet, connection) => { 66 | const buddyObj = { 67 | buddyId: parseInt(packet.params[0]) 68 | }; 69 | 70 | connection.emit(ActionType.BUDDY.NOTIFY_OFFLINE, buddyObj); 71 | }; 72 | 73 | exports.handleSearch = (packet, connection) => { 74 | const buddyObj = { 75 | foundPlayers: packet.params[0] 76 | }; 77 | 78 | connection.emit(ActionType.BUDDY.SEARCH, buddyObj); 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /src/events/engineEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const logger = require("../utils/logger"); 4 | const config = require("../config"); 5 | 6 | exports.handleGetCrumbs = (packet, connection) => { 7 | const crumbObj = { 8 | type: packet.params[0], 9 | crumbs: packet.params[1] 10 | }; 11 | 12 | if (config.debug) { 13 | logger.debug(`[Crumbs Received] Successfully parsed ${crumbObj.type} crumbs`); 14 | } 15 | 16 | connection.crumbs[crumbObj.type] = JSON.parse(crumbObj.crumbs); 17 | connection.emit(ActionType.ENGINE.GET_CRUMBS, crumbObj); 18 | }; 19 | 20 | 21 | exports.handleGetPlayer = (packet, connection) => { 22 | const playerObj = { 23 | player: packet.params[0], 24 | cause: packet.params[1] 25 | }; 26 | 27 | connection.emit(ActionType.ENGINE.GET_PLAYER, playerObj); 28 | }; 29 | 30 | exports.handleGetPrompt = (packet, connection) => { 31 | const promptObj = { 32 | type: packet.params[0], 33 | message: packet.params[1] 34 | }; 35 | 36 | connection.emit(ActionType.ENGINE.GET_PROMPT, promptObj); 37 | }; 38 | -------------------------------------------------------------------------------- /src/events/gameEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleGameOver = (packet, connection) => { 4 | const gameObj = { 5 | coins: { 6 | total: parseInt(packet.params[0]), 7 | gained: parseInt(packet.params[1]) 8 | }, 9 | room: { 10 | spawn: { 11 | x: parseInt(packet.params[2]), 12 | y: parseInt(packet.params[3]) 13 | } 14 | } 15 | }; 16 | 17 | connection.emit(ActionType.GAME.OVER, gameObj); 18 | }; 19 | -------------------------------------------------------------------------------- /src/events/ignoreEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleGetIgnored = (packet, connection) => { 4 | const ignoredObj = { 5 | ignored: packet.params[0] 6 | }; 7 | 8 | connection.emit(ActionType.IGNORE.GET_IGNORED, ignoredObj); 9 | }; 10 | -------------------------------------------------------------------------------- /src/events/inventoryEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleGetInventory = (packet, connection) => { 4 | const invObj = { 5 | itemIdList: packet.params[0] 6 | }; 7 | 8 | connection.emit(ActionType.INVENTORY.GET_INVENTORY, invObj); 9 | }; 10 | 11 | exports.handleBuyInventory = (packet, connection) => { 12 | const invObj = { 13 | itemId: parseInt(packet.params[0]) 14 | }; 15 | 16 | connection.emit(ActionType.INVENTORY.BUY_INVENTORY, invObj); 17 | }; 18 | -------------------------------------------------------------------------------- /src/events/loginEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const ActionType = require('../enums/actionType'); 4 | 5 | /* 6 | {"action":"login:u","params":[ 7 | id, --- penguinId 8 | "user", ---- username 9 | "TOKEN_HERE", --- token (world auth) 10 | 11 | {"id":id,"swid":"{63227f9b-dcc0-fcaf-7317-6284befba3f6}","username":"user","nickname":"nick","moderator":false,"rank":0,"color":0,"head":0,"face":0,"neck":0,"body":0,"hand":0,"feet":0,"photo":0,"pin":0,"isMascot":false,"giftId":0,"coins":0,"minutesPlayed":0,"age":0}, --- penguin string 12 | 13 | {"blizzard":{"english":"Blizzard","host":"server.cprewritten.net","port":"7071","population":0,"id":100,"safe_chat":false,"buddy_online":false},"zipline":{"english":"Zipline","host":"server.cprewritten.net","port":"7072","population":0,"id":101,"safe_chat":false,"buddy_online":false},"abominable":{"english":"Abominable","host":"server.cprewritten.net","port":"7073","population":0,"id":102,"safe_chat":false,"buddy_online":false},"ascent":{"english":"Ascent","host":"server.cprewritten.net","port":"7075","population":0,"id":104,"safe_chat":false,"buddy_online":false}}, --- worlds list 14 | 15 | 1596571841056, --- unknown 16 | 8, --- unknown 17 | "[^A-Za-z!\" ?😂🤣🤡🥺❤️💞💅]+" --- chat regex 18 | */ 19 | 20 | exports.handleUserLogin = (packet, connection) => { 21 | const loginObj = { 22 | playerId: packet.params[0], 23 | username: packet.params[1], 24 | token: packet.params[2], 25 | penguinString: packet.params[3], 26 | worldList: packet.params[4] 27 | }; 28 | 29 | connection.crumbs.servers = loginObj.worldList; 30 | connection.emit(ActionType.USER.LOGIN, loginObj); 31 | }; 32 | -------------------------------------------------------------------------------- /src/events/navigationEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleJoinRoom = (packet, connection) => { 4 | const roomObj = { 5 | roomId: parseInt(packet.params[0]), 6 | x: parseInt(packet.params[1]), 7 | y: parseInt(packet.params[2]) 8 | }; 9 | 10 | connection.emit(ActionType.NAVIGATION.JOIN_ROOM, roomObj); 11 | }; 12 | 13 | exports.handleAddPlayer = (packet, connection) => { 14 | const playerObj = { 15 | x: parseInt(packet.params[0]), 16 | y: parseInt(packet.params[1]), 17 | playerId: parseInt(packet.params[2]), 18 | username: packet.params[3], 19 | penguinString: packet.params[4] 20 | }; 21 | 22 | connection.emit(ActionType.NAVIGATION.ADD_PLAYER, playerObj); 23 | }; 24 | 25 | exports.handleRemovePlayer = (packet, connection) => { 26 | const playerObj = { 27 | playerId: parseInt(packet.params[0]) 28 | }; 29 | 30 | connection.emit(ActionType.NAVIGATION.REMOVE_PLAYER, playerObj); 31 | }; 32 | -------------------------------------------------------------------------------- /src/events/playerEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleMove = (packet, connection) => { 4 | const moveObj = { 5 | playerId: parseInt(packet.params[0]), 6 | x: parseInt(packet.params[1]), 7 | y: parseInt(packet.params[2]) 8 | }; 9 | 10 | connection.emit(ActionType.PLAYER.MOVE, moveObj); 11 | }; 12 | 13 | exports.handleMessage = (packet, connection) => { 14 | const msgObj = { 15 | playerId: parseInt(packet.params[0]), 16 | message: packet.params[1] 17 | }; 18 | 19 | connection.emit(ActionType.PLAYER.MESSAGE, msgObj); 20 | }; 21 | 22 | exports.handleUpdateWearing = (packet, connection) => { 23 | const wearingObj = { 24 | playerId: parseInt(packet.params[0]), 25 | itemType: packet.params[1], 26 | itemId: parseInt(packet.params[2]) 27 | }; 28 | 29 | connection.emit(ActionType.PLAYER.UPDATE_WEARING, wearingObj); 30 | }; 31 | 32 | exports.handleAction = (packet, connection) => { 33 | const actionObj = { 34 | playerId: parseInt(packet.params[0]), 35 | type: packet.params[1], 36 | actionData: packet.params[2], 37 | }; 38 | 39 | connection.emit(ActionType.PLAYER.ACTION, actionObj); 40 | }; 41 | 42 | exports.handleEmote = (packet, connection) => { 43 | const emoteObj = { 44 | playerId: parseInt(packet.params[0]), 45 | emote: packet.params[1] 46 | }; 47 | 48 | connection.emit(ActionType.PLAYER.EMOTE, emoteObj); 49 | }; 50 | -------------------------------------------------------------------------------- /src/events/worldEvents.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | exports.handleWorldAuth = (packet, connection) => { 4 | const worldObj = { 5 | playerId: packet.params[0], 6 | username: packet.params[1], 7 | penguinString: packet.params[2] 8 | }; 9 | 10 | const crumbTypes = ['item', 'room', 'game']; 11 | crumbTypes.forEach(crumb => connection.sendPacket(ActionType.ENGINE.GET_CRUMBS, [crumb])); 12 | 13 | connection.isLoggedIn = true; 14 | connection.emit(ActionType.WORLD.AUTHENTICATE, worldObj); 15 | }; 16 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const logger = require('./utils/logger'); 4 | const config = require('./config'); 5 | const actionType = require('./enums/actionType'); 6 | const CryptoUtils = require('./utils/cryptoUtils'); 7 | 8 | global.logger = logger; 9 | global.config = config; 10 | global.ActionType = actionType; 11 | global.cryptoUtils = new CryptoUtils(); 12 | 13 | console.log("Welcome to CPR Client Library"); 14 | 15 | // If you want, replace example with your own script for now. NPM module will be coming soon! 16 | const ItemAdder = require('../scripts/itemAdder'); 17 | 18 | const { username, password, delay, freeOnly } = config.scripts.itemAdder; 19 | ItemAdder.run({ username, password, delay, freeOnly }); 20 | -------------------------------------------------------------------------------- /src/networking/connection.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const io = require('socket.io-client'); 4 | const Emitter = require('component-emitter'); 5 | 6 | const buddyEvents = require('../events/buddyEvents'); 7 | const engineEvents = require('../events/engineEvents'); 8 | const gameEvents = require('../events/gameEvents'); 9 | const ignoreEvents = require('../events/ignoreEvents'); 10 | const inventoryEvents = require('../events/inventoryEvents'); 11 | const loginEvents = require('../events/loginEvents'); 12 | const navigationEvents = require('../events/navigationEvents'); 13 | const playerEvents = require('../events/playerEvents'); 14 | const worldEvents = require('../events/worldEvents'); 15 | 16 | module.exports = class Connection { 17 | constructor(ip, port) { 18 | Emitter(Connection.prototype); 19 | 20 | this.ip = ip; 21 | this.port = port; 22 | 23 | this.socket = io(`${this.ip}:${this.port}`, { 24 | transports: ['websocket'], 25 | autoConnect: false 26 | }); 27 | 28 | this.socket.on('connect', () => { 29 | logger.info(`Connected to CPR ${port === 7070 ? 'login' : 'game'} server.`); 30 | }); 31 | this.socket.on('disconnect', () => { 32 | logger.error(`Disconnected from CPR ${port === 7070 ? 'login' : 'game'} server.`); 33 | }); 34 | this.socket.on('p', (data) => { 35 | const dataAsJson = JSON.parse(data); 36 | this.handlePacket(dataAsJson); 37 | }); 38 | 39 | this.isLoggedIn = false; 40 | this.crumbs = { servers: null, item: null, room: null, game: null }; 41 | 42 | this.listeners = { 43 | 'login': { 44 | 'u': loginEvents.handleUserLogin 45 | }, 46 | 'world': { 47 | 'auth': worldEvents.handleWorldAuth 48 | }, 49 | 'engine': { 50 | 'get_crumbs': engineEvents.handleGetCrumbs, 51 | 'get_player': engineEvents.handleGetPlayer, 52 | 'prompt': engineEvents.handleGetPrompt 53 | }, 54 | 'ignore': { 55 | 'get_ignored': ignoreEvents.handleGetIgnored 56 | }, 57 | 'navigation': { 58 | 'add_player': navigationEvents.handleAddPlayer, 59 | 'join_room': navigationEvents.handleJoinRoom, 60 | 'remove_player': navigationEvents.handleRemovePlayer 61 | }, 62 | 'player': { 63 | 'action': playerEvents.handleAction, 64 | 'emote': playerEvents.handleEmote, 65 | 'message': playerEvents.handleMessage, 66 | 'move': playerEvents.handleMove, 67 | 'update_wearing': playerEvents.handleUpdateWearing 68 | }, 69 | 'buddy': { 70 | 'add_buddy': buddyEvents.handleAddBuddy, 71 | 'find_buddy': buddyEvents.handleFindBuddy, 72 | 'get_buddies': buddyEvents.handleGetBuddies, 73 | 'notify_online': buddyEvents.handleNotifyOnline, 74 | 'notify_offline': buddyEvents.handleNotifyOffline, 75 | 'remove_buddy': buddyEvents.handleRemoveBuddy, 76 | 'request_buddy': buddyEvents.handleRequestBuddy, 77 | 'search': buddyEvents.handleSearch, 78 | }, 79 | 'inventory': { 80 | 'buy_inventory': inventoryEvents.handleBuyInventory, 81 | 'get_inventory': inventoryEvents.handleGetInventory 82 | }, 83 | 'game': { 84 | 'over': gameEvents.handleGameOver 85 | } 86 | }; 87 | } 88 | 89 | handlePacket(packetObj) { 90 | const [action, type] = packetObj.action.split(':'); 91 | (config.debug && type !== 'get_crumbs') ? 92 | logger.incoming(packetObj) : null; 93 | if (!this.listeners[action] || !this.listeners[action][type]) { 94 | logger.error(`Failed to parse packet of type '${action}:${type}'`); 95 | return; 96 | } 97 | this.listeners[action][type](packetObj, this); 98 | } 99 | 100 | sendPacket(action, params = []) { 101 | const packet = {action, params}; 102 | config.debug ? logger.outgoing(packet) : null; 103 | this.socket.emit('p', packet); 104 | } 105 | 106 | getCrumb(type) { 107 | if (!this.isLoggedIn) { 108 | logger.error('Cannot get crumbs before logging into the server. Please call login method to continue.'); 109 | } else if (!this.crumbs[type] || this.crumbs[type] === null) { 110 | const joined = Object.keys(this.crumbs).join(', '); 111 | logger.error(`Crumbs of type '${type}' could not be found. Please try: ${joined}.`); 112 | } else { 113 | return this.crumbs[type]; 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/networking/penguin.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const Connection = require('./connection'); 4 | 5 | module.exports = class Penguin { 6 | constructor(username, password) { 7 | const { ip, port } = config.servers.login; 8 | this.connection = new Connection(ip, port); 9 | 10 | this.username = username; 11 | this.password = password; 12 | 13 | this.currentRoom = {}; 14 | } 15 | 16 | login(object) { 17 | return new Promise((resolve, reject) => { 18 | if (this.connection.isLoggedIn) { 19 | reject(new Error(`${username} has already logged into CPR!`)); 20 | return; 21 | } 22 | 23 | this.connection.socket.connect(); 24 | 25 | this.connection.once(ActionType.USER.LOGIN, (packet) => { 26 | config.debug ? logger.debug(`Received token ${packet.token}`) : null; 27 | this.worldToken = packet.token; 28 | }); 29 | 30 | this.connection.socket.once('connect', () => { 31 | const hashedPassword = cryptoUtils.hashPasswordCP(this.password); 32 | this.connection.sendPacket(ActionType.USER.LOGIN, [this.username, hashedPassword]); 33 | }); 34 | 35 | this.connection.socket.once('disconnect', () => { 36 | const serverName = object.server.toLowerCase(); 37 | this.connectToWorld(serverName) 38 | .then(() => resolve()) 39 | .catch(err => reject(err)); 40 | }); 41 | }); 42 | } 43 | 44 | connectToWorld(serverName) { 45 | return new Promise((resolve, reject) => { 46 | const { servers } = this.connection.crumbs; 47 | 48 | if (!servers || !servers[serverName]) { 49 | const joined = Object.keys(servers).join(', '); 50 | logger.error(`Could not find server '${serverName}' in crumbs. Please try: ${joined}`); 51 | return; 52 | } 53 | 54 | const { host, port } = servers[serverName]; 55 | 56 | this.connection = new Connection(`https://${host}`, port); 57 | this.connection.socket.connect(); 58 | 59 | this.connection.once(ActionType.WORLD.AUTHENTICATE, () => { 60 | this.connection.isLoggedIn ? resolve() : reject(new Error('Failed to login')); 61 | }); 62 | 63 | this.connection.socket.once('connect', () => { 64 | this.connection.sendPacket(ActionType.WORLD.AUTHENTICATE, [this.worldToken]); 65 | }); 66 | }); 67 | } 68 | 69 | buddySearch(name) { 70 | return new Promise(resolve => { 71 | this.connection.sendPacket(ActionType.BUDDY.SEARCH, [name]); 72 | this.connection.once(ActionType.BUDDY.SEARCH, (packet) => { 73 | resolve(packet); 74 | }); 75 | }); 76 | } 77 | 78 | move(x, y) { 79 | this.connection.sendPacket(ActionType.PLAYER.MOVE, [x, y]); 80 | } 81 | 82 | getPlayer(id) { 83 | // Default the cause to 'buddy_playercard_open' since I haven't tested if the server will kick for sending an invalid cause yet 84 | const cause = 'buddy_playercard_open'; 85 | return new Promise(resolve => { 86 | this.connection.sendPacket(ActionType.ENGINE.GET_PLAYER, [id, cause]); 87 | this.connection.once(ActionType.ENGINE.GET_PLAYER, (packet) => { 88 | resolve(packet); 89 | }); 90 | }); 91 | } 92 | 93 | getBuddies() { 94 | return new Promise(resolve => { 95 | this.connection.sendPacket(ActionType.BUDDY.GET_BUDDIES); 96 | this.connection.once(ActionType.BUDDY.GET_BUDDIES, (packet) => { 97 | resolve(packet); 98 | }); 99 | }); 100 | } 101 | 102 | requestBuddy(id) { 103 | this.connection.sendPacket(ActionType.BUDDY.REQUEST_BUDDY, [id]); 104 | } 105 | 106 | addBuddy(id) { 107 | this.connection.sendPacket(ActionType.BUDDY.REQUEST_BUDDY, [id]); 108 | } 109 | 110 | removeBuddy(id) { 111 | this.connection.sendPacket(ActionType.BUDDY.REMOVE_BUDDY, [id]); 112 | } 113 | 114 | getIgnored() { 115 | return new Promise(resolve => { 116 | this.connection.sendPacket(ActionType.INVENTORY.GET_IGNORED); 117 | this.connection.once(ActionType.INVENTORY.GET_IGNORED, (packet) => { 118 | resolve(packet); 119 | }); 120 | }); 121 | } 122 | 123 | buyItem(id) { 124 | this.connection.sendPacket(ActionType.INVENTORY.BUY_INVENTORY, [id]); 125 | } 126 | 127 | joinRoom(id, x, y) { 128 | //TODO support for string as ID param (parse room crumbs) 129 | this.connection.sendPacket(ActionType.NAVIGATION.JOIN_ROOM, [id, x, y]); 130 | } 131 | 132 | sendMessage(message) { 133 | this.connection.sendPacket(ActionType.PLAYER.MESSAGE, [message]); 134 | } 135 | 136 | sendEmote(id) { 137 | this.connection.sendPacket(ActionType.PLAYER.EMOTE, [`e${id}`]); 138 | } 139 | 140 | getInventory() { 141 | return new Promise(resolve => { 142 | this.connection.sendPacket(ActionType.INVENTORY.GET_INVENTORY); 143 | this.connection.once(ActionType.INVENTORY.GET_INVENTORY, (packet) => { 144 | resolve(packet); 145 | }); 146 | }); 147 | } 148 | 149 | updateWearing(itemType, itemId = 0) { 150 | this.connection.sendPacket(ActionType.PLAYER.UPDATE_WEARING, [itemType, itemId]); 151 | } 152 | 153 | performAction(type, actionData) { 154 | //TODO verify action type 155 | this.connection.sendPacket(ActionType.PLAYER.ACTION, [type, actionData]); 156 | } 157 | 158 | addCoins(amount) { 159 | //TODO Verify max amount of coins that client can add before being kicked --- play it safe for now 160 | if (amount >= 50000) { 161 | logger.error('You tried to add too many coins. Please try a number below 50,000!'); 162 | return; 163 | } 164 | 165 | //TODO verify x and y exit spawn coords depending on user's current game room 166 | this.connection.sendPacket(ActionType.GAME.OVER, [amount, 407, 692]); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/utils/cryptoUtils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // thx gravix ily <3 4 | module.exports = class CryptoUtils { 5 | swapMD5(password) { 6 | return password.substr(16, 16) + password.substr(0, 16); 7 | } 8 | 9 | hashPasswordCP(password) { 10 | password = this.md5(password) 11 | return this.swapMD5(this.md5(this.swapMD5(password.toUpperCase()) + 'a94c5ed2140fc249ee3ce0729e19af5a' + 'Y(02.>\'H}t":E1')); 12 | } 13 | 14 | md5(string) { 15 | function RotateLeft(lValue, iShiftBits) { 16 | return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); 17 | } 18 | 19 | function AddUnsigned(lX, lY) { 20 | var lX4, lY4, lX8, lY8, lResult; 21 | lX8 = (lX & 0x80000000); 22 | lY8 = (lY & 0x80000000); 23 | lX4 = (lX & 0x40000000); 24 | lY4 = (lY & 0x40000000); 25 | lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF); 26 | if (lX4 & lY4) { 27 | return (lResult ^ 0x80000000 ^ lX8 ^ lY8); 28 | } 29 | if (lX4 | lY4) { 30 | if (lResult & 0x40000000) { 31 | return (lResult ^ 0xC0000000 ^ lX8 ^ lY8); 32 | } else { 33 | return (lResult ^ 0x40000000 ^ lX8 ^ lY8); 34 | } 35 | } else { 36 | return (lResult ^ lX8 ^ lY8); 37 | } 38 | } 39 | 40 | function F(x, y, z) { 41 | return (x & y) | ((~x) & z); 42 | } 43 | 44 | function G(x, y, z) { 45 | return (x & z) | (y & (~z)); 46 | } 47 | 48 | function H(x, y, z) { 49 | return (x ^ y ^ z); 50 | } 51 | 52 | function I(x, y, z) { 53 | return (y ^ (x | (~z))); 54 | } 55 | 56 | function FF(a, b, c, d, x, s, ac) { 57 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac)); 58 | return AddUnsigned(RotateLeft(a, s), b); 59 | }; 60 | 61 | function GG(a, b, c, d, x, s, ac) { 62 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac)); 63 | return AddUnsigned(RotateLeft(a, s), b); 64 | }; 65 | 66 | function HH(a, b, c, d, x, s, ac) { 67 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac)); 68 | return AddUnsigned(RotateLeft(a, s), b); 69 | }; 70 | 71 | function II(a, b, c, d, x, s, ac) { 72 | a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac)); 73 | return AddUnsigned(RotateLeft(a, s), b); 74 | }; 75 | 76 | function ConvertToWordArray(string) { 77 | var lWordCount; 78 | var lMessageLength = string.length; 79 | var lNumberOfWords_temp1 = lMessageLength + 8; 80 | var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64; 81 | var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16; 82 | var lWordArray = Array(lNumberOfWords - 1); 83 | var lBytePosition = 0; 84 | var lByteCount = 0; 85 | while (lByteCount < lMessageLength) { 86 | lWordCount = (lByteCount - (lByteCount % 4)) / 4; 87 | lBytePosition = (lByteCount % 4) * 8; 88 | lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition)); 89 | lByteCount++; 90 | } 91 | lWordCount = (lByteCount - (lByteCount % 4)) / 4; 92 | lBytePosition = (lByteCount % 4) * 8; 93 | lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition); 94 | lWordArray[lNumberOfWords - 2] = lMessageLength << 3; 95 | lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29; 96 | return lWordArray; 97 | }; 98 | 99 | function WordToHex(lValue) { 100 | var WordToHexValue = "", 101 | WordToHexValue_temp = "", 102 | lByte, lCount; 103 | for (lCount = 0; lCount <= 3; lCount++) { 104 | lByte = (lValue >>> (lCount * 8)) & 255; 105 | WordToHexValue_temp = "0" + lByte.toString(16); 106 | WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2); 107 | } 108 | return WordToHexValue; 109 | }; 110 | 111 | function Utf8Encode(string) { 112 | string = string.replace(/\r\n/g, "\n"); 113 | var utftext = ""; 114 | for (var n = 0; n < string.length; n++) { 115 | var c = string.charCodeAt(n); 116 | if (c < 128) { 117 | utftext += String.fromCharCode(c); 118 | } else if ((c > 127) && (c < 2048)) { 119 | utftext += String.fromCharCode((c >> 6) | 192); 120 | utftext += String.fromCharCode((c & 63) | 128); 121 | } else { 122 | utftext += String.fromCharCode((c >> 12) | 224); 123 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 124 | utftext += String.fromCharCode((c & 63) | 128); 125 | } 126 | } 127 | return utftext; 128 | }; 129 | var x = Array(); 130 | var k, AA, BB, CC, DD, a, b, c, d; 131 | var S11 = 7, 132 | S12 = 12, 133 | S13 = 17, 134 | S14 = 22; 135 | var S21 = 5, 136 | S22 = 9, 137 | S23 = 14, 138 | S24 = 20; 139 | var S31 = 4, 140 | S32 = 11, 141 | S33 = 16, 142 | S34 = 23; 143 | var S41 = 6, 144 | S42 = 10, 145 | S43 = 15, 146 | S44 = 21; 147 | string = Utf8Encode(string); 148 | x = ConvertToWordArray(string); 149 | a = 0x67452301; 150 | b = 0xEFCDAB89; 151 | c = 0x98BADCFE; 152 | d = 0x10325476; 153 | for (k = 0; k < x.length; k += 16) { 154 | AA = a; 155 | BB = b; 156 | CC = c; 157 | DD = d; 158 | a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478); 159 | d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756); 160 | c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB); 161 | b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE); 162 | a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF); 163 | d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A); 164 | c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613); 165 | b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501); 166 | a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8); 167 | d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF); 168 | c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1); 169 | b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE); 170 | a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122); 171 | d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193); 172 | c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E); 173 | b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821); 174 | a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562); 175 | d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340); 176 | c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51); 177 | b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA); 178 | a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D); 179 | d = GG(d, a, b, c, x[k + 10], S22, 0x2441453); 180 | c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681); 181 | b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8); 182 | a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6); 183 | d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6); 184 | c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87); 185 | b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED); 186 | a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905); 187 | d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8); 188 | c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9); 189 | b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A); 190 | a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942); 191 | d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681); 192 | c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122); 193 | b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C); 194 | a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44); 195 | d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9); 196 | c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60); 197 | b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70); 198 | a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6); 199 | d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA); 200 | c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085); 201 | b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05); 202 | a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039); 203 | d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5); 204 | c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8); 205 | b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665); 206 | a = II(a, b, c, d, x[k + 0], S41, 0xF4292244); 207 | d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97); 208 | c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7); 209 | b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039); 210 | a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3); 211 | d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92); 212 | c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D); 213 | b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1); 214 | a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F); 215 | d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0); 216 | c = II(c, d, a, b, x[k + 6], S43, 0xA3014314); 217 | b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1); 218 | a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82); 219 | d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235); 220 | c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB); 221 | b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391); 222 | a = AddUnsigned(a, AA); 223 | b = AddUnsigned(b, BB); 224 | c = AddUnsigned(c, CC); 225 | d = AddUnsigned(d, DD); 226 | } 227 | var temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d); 228 | return temp.toLowerCase(); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/utils/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // thx zaseth ily <3 4 | 5 | const { createLogger, transports, format, addColors } = require('winston') 6 | const { combine, colorize, timestamp, json, printf } = format 7 | 8 | require('winston-daily-rotate-file') 9 | addColors({ 10 | incoming: 'bold white cyanBG', 11 | outgoing: 'bold white yellowBG', 12 | extension: 'bold magenta blackBG' 13 | }) 14 | 15 | /** 16 | * @description The text formatter 17 | * @param {String} level 18 | * @param {String} message 19 | * @param {String} timestamp 20 | * @returns {String} 21 | */ 22 | const textFormat = printf(({ level, message, timestamp }) => { 23 | return `[\x1b[36m${timestamp}\x1b[0m] [${level}] \x1b[35m>\x1b[0m ${message}` 24 | }) 25 | 26 | /** 27 | * @description The JSON formatter 28 | * @param {String} level 29 | * @param {Object} message 30 | * @param {String} timestamp 31 | * @returns {String} 32 | */ 33 | const jsonFormat = printf(({ level, message, timestamp }) => { 34 | return `[\x1b[36m${timestamp}\x1b[0m] [${level}] \x1b[35m>\x1b[0m ${JSON.stringify(message, null, 4)}` 35 | }) 36 | 37 | /** 38 | * @description The debug logger 39 | * @type {winston.Logger} 40 | */ 41 | const { debug } = createLogger({ 42 | levels: { debug: 7 }, 43 | transports: [ 44 | new transports.DailyRotateFile({ 45 | level: 'debug', 46 | maxFiles: '1d', 47 | filename: `./logs/${process.argv[2]}/debug@%DATE%.log`, 48 | datePattern: 'D-M-YYYY', 49 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 50 | }), 51 | new transports.Console({ 52 | level: 'debug', 53 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), textFormat) 54 | }) 55 | ] 56 | }) 57 | 58 | /** 59 | * @description The info logger 60 | * @type {winston.Logger} 61 | */ 62 | const { info } = createLogger({ 63 | levels: { info: 6 }, 64 | transports: [ 65 | new transports.DailyRotateFile({ 66 | level: 'info', 67 | maxFiles: '2d', 68 | filename: `./logs/${process.argv[2]}/info@%DATE%.log`, 69 | datePattern: 'D-M-YYYY', 70 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 71 | }), 72 | new transports.Console({ 73 | level: 'info', 74 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), textFormat) 75 | }) 76 | ] 77 | }) 78 | 79 | /** 80 | * @description The warn logger 81 | * @type {winston.Logger} 82 | */ 83 | const { warn } = createLogger({ 84 | levels: { warn: 4 }, 85 | transports: [ 86 | new transports.DailyRotateFile({ 87 | level: 'warn', 88 | maxFiles: '3d', 89 | filename: `./logs/${process.argv[2]}/warn@%DATE%.log`, 90 | datePattern: 'D-M-YYYY', 91 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 92 | }), 93 | new transports.Console({ 94 | level: 'warn', 95 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), textFormat) 96 | }) 97 | ] 98 | }) 99 | 100 | /** 101 | * @description The error logger 102 | * @type {winston.Logger} 103 | */ 104 | const { error } = createLogger({ 105 | levels: { error: 3 }, 106 | transports: [ 107 | new transports.DailyRotateFile({ 108 | level: 'error', 109 | maxFiles: '3d', 110 | filename: `./logs/${process.argv[2]}/error@%DATE%.log`, 111 | datePattern: 'D-M-YYYY', 112 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 113 | }), 114 | new transports.Console({ 115 | level: 'error', 116 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), textFormat) 117 | }) 118 | ] 119 | }) 120 | 121 | /** 122 | * @description The incoming logger 123 | * @type {winston.Logger} 124 | */ 125 | const { incoming } = createLogger({ 126 | levels: { incoming: 6 }, 127 | transports: [ 128 | new transports.DailyRotateFile({ 129 | level: 'incoming', 130 | maxFiles: '2d', 131 | filename: `./logs/${process.argv[2]}/incoming@%DATE%.log`, 132 | datePattern: 'D-M-YYYY', 133 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 134 | }), 135 | new transports.Console({ 136 | level: 'incoming', 137 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), jsonFormat) 138 | }) 139 | ] 140 | }) 141 | 142 | /** 143 | * @description The outgoing logger 144 | * @type {winston.Logger} 145 | */ 146 | const { outgoing } = createLogger({ 147 | levels: { outgoing: 6 }, 148 | transports: [ 149 | new transports.DailyRotateFile({ 150 | level: 'outgoing', 151 | maxFiles: '2d', 152 | filename: `./logs/${process.argv[2]}/outgoing@%DATE%.log`, 153 | datePattern: 'D-M-YYYY', 154 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 155 | }), 156 | new transports.Console({ 157 | level: 'outgoing', 158 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), jsonFormat) 159 | }) 160 | ] 161 | }) 162 | 163 | /** 164 | * @description The extension logger 165 | * @type {winston.Logger} 166 | */ 167 | const { extension } = createLogger({ 168 | levels: { extension: 6 }, 169 | transports: [ 170 | new transports.DailyRotateFile({ 171 | level: 'extension', 172 | maxFiles: '2d', 173 | filename: `./logs/${process.argv[2]}/extension@%DATE%.log`, 174 | datePattern: 'D-M-YYYY', 175 | format: combine(timestamp({ format: 'HH:mm:ss' }), json()) 176 | }), 177 | new transports.Console({ 178 | level: 'extension', 179 | format: combine(colorize(), timestamp({ format: 'HH:mm:ss' }), textFormat) 180 | }) 181 | ] 182 | }) 183 | 184 | /** 185 | * @exports 186 | */ 187 | module.exports = { 188 | debug: (msg) => debug(msg), 189 | info: (msg) => info(msg), 190 | warn: (msg) => warn(msg), 191 | error: (msg) => error(msg), 192 | incoming: (msg) => incoming(msg), 193 | outgoing: (msg) => outgoing(msg), 194 | extension: (msg) => extension(msg) 195 | } 196 | --------------------------------------------------------------------------------