├── .deepsource.toml ├── .github └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── HttpProxyService.lua ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── package-lock.json ├── package.json └── server.js /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "javascript" 5 | enabled = true -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ main ] 20 | schedule: 21 | - cron: '41 21 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v2 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v2 71 | -------------------------------------------------------------------------------- /.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 | # TypeScript v1 declaration files 45 | typings/ 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 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /HttpProxyService.lua: -------------------------------------------------------------------------------- 1 | local HttpProxyService = {} 2 | 3 | local HttpService = game:GetService("HttpService") 4 | 5 | local Url = "" -- Your URL here. Example: https://app-name-here.herokuapp.com (Without '/' at the end) 6 | 7 | function IsTable(Object) 8 | if typeof(Object) == "table" then 9 | return true 10 | else 11 | return false 12 | end 13 | end 14 | 15 | function GetUrl(Method, Link, Password) 16 | return HttpProxyService:FormatParams(Url .. Method, { 17 | password = Password, 18 | url = HttpService:UrlEncode(Link) 19 | }) 20 | end 21 | 22 | function HttpProxyService:New(Password) 23 | local Functions = {} 24 | 25 | function Functions:GetAsync(Link, Decode, FakeHeaders) 26 | if FakeHeaders == nil then 27 | FakeHeaders = {} 28 | end 29 | 30 | if IsTable(FakeHeaders) then 31 | FakeHeaders = HttpService:JSONEncode(FakeHeaders) 32 | end 33 | 34 | local Response = HttpService:RequestAsync({ 35 | Url = GetUrl("/get", Link, Password), 36 | Method = "POST", 37 | Headers = { 38 | ["Content-Type"] = "application/json" 39 | }, 40 | Body = FakeHeaders 41 | }).Body 42 | 43 | local DecodedResponse = HttpService:JSONDecode(Response) 44 | 45 | if DecodedResponse.error then 46 | warn(DecodedResponse.error.message) 47 | 48 | return DecodedResponse 49 | end 50 | 51 | if Decode == nil or Decode then 52 | return DecodedResponse 53 | else 54 | return Response 55 | end 56 | end 57 | 58 | function Functions:PostAsync(Link, Decode, Data, Headers) 59 | local Body = HttpService:JSONEncode({ 60 | Data = Data or {}, 61 | Headers = Headers or {} 62 | }) 63 | 64 | local Response = HttpService:RequestAsync({ 65 | Url = GetUrl("/post", Link, Password), 66 | Method = "POST", 67 | Headers = { 68 | ["Content-Type"] = "application/json" 69 | }, 70 | Body = Body 71 | }).Body 72 | 73 | local DecodedResponse = HttpService:JSONDecode(Response) 74 | 75 | if DecodedResponse.error then 76 | warn(DecodedResponse.error.message) 77 | 78 | return DecodedResponse 79 | end 80 | 81 | if Decode == nil or Decode then 82 | return DecodedResponse 83 | else 84 | return Response 85 | end 86 | end 87 | 88 | function Functions:PatchAsync(Link, Decode, Data, Headers) 89 | local Body = HttpService:JSONEncode({ 90 | Data = Data or {}, 91 | Headers = Headers or {} 92 | }) 93 | 94 | local Response = HttpService:RequestAsync({ 95 | Url = GetUrl("/patch", Link, Password), 96 | Method = "POST", 97 | Headers = { 98 | ["Content-Type"] = "application/json" 99 | }, 100 | Body = Body 101 | }).Body 102 | 103 | local DecodedResponse = HttpService:JSONDecode(Response) 104 | 105 | if DecodedResponse.error then 106 | warn(DecodedResponse.error.message) 107 | 108 | return DecodedResponse 109 | end 110 | 111 | if Decode == nil or Decode then 112 | return DecodedResponse 113 | else 114 | return Response 115 | end 116 | end 117 | 118 | function Functions:DeleteAsync(Link, Decode, FakeHeaders) 119 | if FakeHeaders == nil then 120 | FakeHeaders = {} 121 | end 122 | 123 | if IsTable(FakeHeaders) then 124 | FakeHeaders = HttpService:JSONEncode(FakeHeaders) 125 | end 126 | 127 | local Response = HttpService:RequestAsync({ 128 | Url = GetUrl("/delete", Link, Password), 129 | Method = "POST", 130 | Headers = { 131 | ["Content-Type"] = "application/json" 132 | }, 133 | Body = FakeHeaders 134 | }).Body 135 | 136 | local DecodedResponse = HttpService:JSONDecode(Response) 137 | 138 | if DecodedResponse.error then 139 | warn(DecodedResponse.error.message) 140 | 141 | return DecodedResponse 142 | end 143 | 144 | if Decode == nil or Decode then 145 | return DecodedResponse 146 | else 147 | return Response 148 | end 149 | end 150 | 151 | return Functions 152 | end 153 | 154 | function HttpProxyService:FormatParams(Link, Params) 155 | if Params == nil then 156 | Params = {} 157 | end 158 | 159 | local First = true 160 | 161 | for Key, Value in pairs(Params) do 162 | if First == true then 163 | Link = Link .. "?" .. Key .. "=" .. Value 164 | 165 | First = false 166 | else 167 | Link = Link .. "&" .. Key .. "=" .. Value 168 | end 169 | end 170 | 171 | return Link 172 | end 173 | 174 | local Proxy = newproxy(true) 175 | local metatable = getmetatable(Proxy) 176 | 177 | metatable.__newindex = function() 178 | error("This ModuleScript is read-only.") 179 | end 180 | 181 | metatable.__index = HttpProxyService 182 | metatable.__metatable = "Metatable is locked." 183 | 184 | return Proxy 185 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Unstable0 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 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HttpProxyService 2 | 3 | THIS IS VERY OUTDATED AND PROLLY DOESNT WORK ANYMORE 4 | ALSO HEROKU REMOVED FREE TIER SO RIP 5 | 6 | Easily Send HTTP Requests to Roblox API/Discord Webhooks 7 | 8 | # Setup 9 | 10 | You will need a [Heroku](https://www.heroku.com) and [GitHub](https://www.github.com) account. 11 | 12 | _Create a [Heroku](https://www.heroku.com) account [here](https://signup.heroku.com) (https://signup.heroku.com) 13 | Login [here](https://id.heroku.com/login) (https://id.heroku.com/login) if you already have a [Heroku](https://www.heroku.com) account_ 14 | 15 | _Create a [Github](https://github.com) account [here](https://github.com/signup?user_email=&source=form-home-signup) (https://github.com/signup?user_email=&source=form-home-signup) 16 | Login [here](https://github.com/login) (https://github.com/login) if you already have a [GitHub](https://github.com) account_ 17 | 18 | - After you are logged into your [Heroku](https://www.heroku.com) account, click [here](https://dashboard.heroku.com/apps) to go to the [dashboard](https://dashboard.heroku.com/apps) (https://dashboard.heroku.com/apps) 19 | 20 | - On the top right, click `New` and click `Create new app` 21 | 22 | ![Screen Shot 2564-11-13 at 11 17 14 AM](https://user-images.githubusercontent.com/46888825/141605439-e2b27ddd-d9a9-44fb-96dd-27b67001fbb7.png) 23 | 24 | - Choose your app name, region and then click `Create app` 25 | 26 | ![Screen Shot 2564-11-13 at 11 18 45 AM](https://user-images.githubusercontent.com/46888825/141605458-fc0f6758-38fd-4534-9f34-f04f899f281c.png) 27 | 28 | - Click on GitHub and click `Connect to GitHub` 29 | 30 | ![Screen Shot 2564-11-13 at 11 21 58 AM](https://user-images.githubusercontent.com/46888825/141647663-c79566f9-4cbd-4c1d-b02e-ac1274e92674.png) 31 | ![Screen Shot 2564-11-13 at 11 23 03 AM](https://user-images.githubusercontent.com/46888825/141647665-9a97aba5-fabe-4fd4-9825-005239933f2a.png) 32 | 33 | - Click `Authorize Heroku` (You have to login into [Github](https://github.com) first) 34 | 35 | ![Screen Shot 2564-11-13 at 11 31 21 AM](https://user-images.githubusercontent.com/46888825/141605716-52563cef-2a17-49d3-af92-b5e95437b9df.png) 36 | 37 | - When you've connected your GitHub account to [Heroku](https://www.heroku.com), you will see this page. 38 | 39 | ![Screen Shot 2564-11-13 at 11 32 40 AM](https://user-images.githubusercontent.com/46888825/141605725-906925eb-3c94-45b0-9ebd-d6eb03e58ef1.png) 40 | 41 | - Fork [this repository](https://github.com/Unstable0/HttpProxyService) (https://github.com/Unstable0/HttpProxyService) 42 | 43 | ![Screen Shot 2564-11-13 at 11 28 09 AM](https://user-images.githubusercontent.com/46888825/141605640-e14a4f1a-8c2e-45aa-9825-a3187b737c4c.png) 44 | 45 | - After you fork this repository, go back to [Heroku](https://www.heroku.com) and search `HttpProxyService` then click `Connect` 46 | 47 | ![Screen Shot 2564-11-13 at 11 34 12 AM](https://user-images.githubusercontent.com/46888825/141605767-d2a79d37-27bb-428c-99cb-1d25de00a8b9.png) 48 | 49 | - Now click `Deploy` and wait until [Heroku](https://www.heroku.com) finish deploying your app 50 | 51 | ![Screen Shot 2564-11-13 at 11 40 00 AM](https://user-images.githubusercontent.com/46888825/141605863-0113ff48-bb8a-483d-8682-85101f24d12c.png) 52 | 53 | - After your app is deployed, click on `View`. 54 | 55 | ![Screen Shot 2564-11-13 at 11 40 29 AM](https://user-images.githubusercontent.com/46888825/141605871-7de372aa-ba97-49d6-b1bf-aa9c4683c80a.png) 56 | 57 | - Copy your app URL, you will need this later. 58 | 59 | ![Screen Shot 2564-11-13 at 11 41 55 AM](https://user-images.githubusercontent.com/46888825/141605911-96640522-1ed9-44f7-b05b-46802dda519d.png) 60 | 61 | 83 | 84 | # Environment Variables Setup 85 | 86 | - Click [here](https://dashboard.heroku.com/apps) to go to your [Heroku](https://www.heroku.com) account [dashboard](https://dashboard.heroku.com/apps) (https://dashboard.heroku.com/apps) 87 | 88 | - Click on your app 89 | 90 | ![Screen Shot 2564-11-13 at 11 56 30 AM](https://user-images.githubusercontent.com/46888825/141606204-42a6f873-99a3-466b-9f4c-b585c56d3f6a.png) 91 | 92 | - Click `Settings` 93 | 94 | ![Screen Shot 2564-11-13 at 6 17 06 PM](https://user-images.githubusercontent.com/46888825/141636176-b8add2da-23dd-48c6-8bab-c7813b207465.png) 95 | 96 | - Click `Reveal Config Vars` 97 | 98 | ![Screen Shot 2564-11-13 at 6 18 11 PM](https://user-images.githubusercontent.com/46888825/141636578-1c56cfcb-a0fa-4dc2-835b-79f12155f696.png) 99 | 100 | - Type your user in the `Key` box and paste your [Roblox](https://www.roblox.com) account cookie inside the `Value` box (You will need this for authentication) 101 | 102 | _Notes: Your user name cannot be `PORT` because it will break the code_ 103 | 104 | ![Screen Shot 2564-11-13 at 6 26 16 PM](https://user-images.githubusercontent.com/46888825/141641856-f90e2fa1-3972-4537-a993-e64652e48730.png) 105 | 106 | ![Screen Shot 2564-11-14 at 7 39 20 AM](https://user-images.githubusercontent.com/46888825/141663252-65c5d983-343c-4dc7-8576-78152a6e0e9a.png) 107 | 108 | - You can add multiple users. 109 | 110 | ![Screen Shot 2564-11-14 at 7 39 47 AM](https://user-images.githubusercontent.com/46888825/141663257-52946684-7dac-4024-ac38-7073e3b204cb.png) 111 | 112 | _Notes: You need to put your full cookie including the \_|WARNING_ 113 | 114 | - Now follow the same steps but type in `password` in the `Key` box and type in your password in the `Value` box (This password will be used to lock your app) 115 | 116 | - You can also use [this website](https://1password.com/password-generator/) (https://1password.com/password-generator/) to generate secure passwords. 117 | 118 | ![Screen Shot 2564-11-14 at 7 40 00 AM](https://user-images.githubusercontent.com/46888825/141663293-ba2ae7f4-fe1b-4ea4-9de4-419705d4a67e.png) 119 | 120 | _Notes: Your password must contain only underscores, letters (a-z), and numbers to prevent problems._ 121 | 122 | - Head over to `Deploy` 123 | 124 | ![Screen Shot 2564-11-14 at 7 40 12 AM](https://user-images.githubusercontent.com/46888825/141663279-b7f24fc7-c8fd-4ada-b655-a454a967e907.png) 125 | 126 | - Scroll down and click `Deploy Branch` 127 | 128 | ![Screen Shot 2564-11-13 at 6 29 28 PM](https://user-images.githubusercontent.com/46888825/141642143-5143e42c-8ffd-49ad-888e-17d1375d3082.png) 129 | 130 | - Now, wait until [Heroku](https://www.heroku.com) finishes deploying your app. 131 | 132 | _Notes: Your [Roblox](https://www.roblox.com) cookie resets every time you log in/out of your account. If you want to use your alt account cookie then open incognito mode and login into your alt account, get your cookie, and close the window so your cookie won't reset._ 133 | 134 | _Every time you update/add/delete a config var, you will have to deploy your app again for the changes to take effect EVEN if you have Automatic Deployment enabled._ 135 | 136 | # Game Setup 137 | 138 | - Create a new [ModuleScript](https://developer.roblox.com/en-us/api-reference/class/ModuleScript) in [ServerStorage](https://developer.roblox.com/en-us/api-reference/class/ServerStorage) and rename it to `HttpProxyService` 139 | 140 | - Replace the code inside your [ModuleScript](https://developer.roblox.com/en-us/api-reference/class/ModuleScript) with this [code](https://github.com/Unstable0/HttpProxyService/blob/main/HttpProxyService.lua) (https://github.com/Unstable0/HttpProxyService/blob/main/HttpProxyService.lua) 141 | 142 | - Go to line 5 where it says `local Url = ""` 143 | 144 | ![Screen Shot 2564-11-12 at 4 56 37 PM](https://user-images.githubusercontent.com/46888825/141448026-e9bb49d6-187d-4f01-9c02-6633339e38ab.png) 145 | 146 | - Paste your [Heroku](https://www.heroku.com) app URL that you copied earlier. 147 | 148 | ![Screen Shot 2564-11-13 at 11 41 55 AM](https://user-images.githubusercontent.com/46888825/141606335-452e3f12-0f8d-4bbb-8c5b-630079a03bac.png) 149 | 150 | ![Screen Shot 2564-11-13 at 11 46 45 AM](https://user-images.githubusercontent.com/46888825/141605997-295663fe-2b01-47da-9754-a873b89ff07f.png) 151 | 152 | (Make sure there is no `/` at the end of your URL) 153 | 154 | # Usage 155 | 156 | ### HttpProxyService:FormatParams 157 | 158 | **Parameters** 159 | 160 | | Name | Type | Default | Required | 161 | | ------ | ----------------------------------------------------------------------------------------- | ------- | -------- | 162 | | url | [string](https://developer.roblox.com/en-us/articles/String) | | true | 163 | | params | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | false | 164 | 165 | **Returns** 166 | 167 | [Formatted URL](https://developer.roblox.com/en-us/articles/String) 168 | 169 | **Example** 170 | 171 | ```lua 172 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 173 | 174 | local FormattedData = HttpProxyService:FormatParams("https://catalog.roblox.com/v1/search/items/details", { 175 | Category = 3, 176 | Keyword = "Pants" 177 | }) 178 | 179 | print(FormattedData) --> https://catalog.roblox.com/v1/search/items/details?Category=3&Keyword=Pants 180 | ``` 181 | 182 | ### HttpProxyService:New 183 | 184 | **Parameters** 185 | 186 | | Name | Type | Default | Description | Required | 187 | | -------- | ------------------------------------------------------------ | ------- | ----------------- | -------- | 188 | | password | [string](https://developer.roblox.com/en-us/articles/String) | | Your app password | true | 189 | 190 | **Returns** 191 | 192 | HttpProxy 193 | 194 | **Examples** 195 | 196 | ```lua 197 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 198 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 199 | 200 | local Data = HttpProxy:GetAsync("https://www.roblox.com") 201 | 202 | print(Data) 203 | ``` 204 | 205 | ### HttpProxy:GetAsync 206 | 207 | **Parameters** 208 | 209 | | Name | Type | Default | Description | Required | 210 | | ------- | ----------------------------------------------------------------------------------------- | ------- | -------------------------------------------- | -------- | 211 | | url | [string](https://developer.roblox.com/en-us/articles/String) | | The web address you are requesting data from | true | 212 | | decode | [bool](https://developer.roblox.com/en-us/articles/Boolean) | true | Whether the request decodes the response | false | 213 | | headers | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | Used to specify some HTTP request headers | false | 214 | 215 | **Returns** 216 | 217 | Response Body 218 | 219 | **Examples** 220 | 221 | Search roblox catalog with the keyword `Pants` and print the results 222 | 223 | ```lua 224 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 225 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 226 | 227 | local FormattedData = HttpProxyService:FormatParams("https://catalog.roblox.com/v1/search/items/details", { 228 | Category = 3, 229 | Keyword = "Pants" 230 | }) 231 | 232 | local Data = HttpProxy:GetAsync(FormattedData) 233 | 234 | for Index, Asset in pairs(Data.data) do 235 | print(Asset.name) 236 | end 237 | ``` 238 | 239 | _If you want to send a get request to Roblox APIs with user credentials, add a `currentuser` header with the user name you added to the config vars. Examples below._ 240 | 241 | Get the friend count for `User1` 242 | 243 | ![Screen Shot 2564-11-14 at 7 39 20 AM](https://user-images.githubusercontent.com/46888825/141663409-00d0f9ee-48fc-4a64-a30f-cb5939eb948a.png) 244 | 245 | ```lua 246 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 247 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 248 | 249 | local Data = HttpProxy:GetAsync("https://friends.roblox.com/v1/my/friends/count", true, { 250 | currentuser = "User1" --Replace with the user you added in the config var (Case sensitive) 251 | }) --> { count: number_of_friends } 252 | 253 | print(Data.count) --> 4 (Number of friends request on the first user) 254 | ``` 255 | 256 | Get the friend count for `User2` 257 | 258 | ![Screen Shot 2564-11-14 at 7 39 47 AM](https://user-images.githubusercontent.com/46888825/141663414-35492743-d1bc-4529-9ca3-939fe0274d09.png) 259 | 260 | ```lua 261 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 262 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 263 | 264 | local Data = HttpProxy:GetAsync("https://friends.roblox.com/v1/my/friends/count", true, { 265 | currentuser = "User2" --Replace with the user you added in the config var (Case sensitive) 266 | }) --> { count: number_of_friends } 267 | 268 | print(Data.count) --> 414 (Number of friends request on the second user) 269 | ``` 270 | 271 | See https://friends.roblox.com/docs#!/Friends/get_v1_my_friends_count 272 | 273 | # HttpProxyService:PostAsync 274 | 275 | **Parameters** 276 | 277 | | Name | Type | Default | Description | Required | 278 | | ------- | ----------------------------------------------------------------------------------------- | ------- | -------------------------------------------- | -------- | 279 | | url | [string](https://developer.roblox.com/en-us/articles/String) | | The web address you are requesting data from | true | 280 | | decode | [bool](https://developer.roblox.com/en-us/articles/Boolean) | true | Whether the request decodes the response | false | 281 | | data | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | The data being sent | false | 282 | | headers | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | Used to specify some HTTP request headers | false | 283 | 284 | **Returns** 285 | 286 | Result 287 | 288 | **Examples** 289 | 290 | Send a `Hello!` message using discord webhook. 291 | 292 | ```lua 293 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 294 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 295 | 296 | HttpProxy:PostAsync("https://discord.com/api/webhooks/123456789012345678/83LgJzu7Qjmfyt1dunqEz651J1jh68kJijwkPaJuJnah7UjjekFgmRhti2_mLakIJneh", true, { 297 | content = "Hello!" 298 | }) 299 | ``` 300 | 301 | ![Screen Shot 2564-11-16 at 8 05 34 PM](https://user-images.githubusercontent.com/46888825/141990519-6682dcfc-dbb8-43f3-a0be-75f6c3385adb.png) 302 | 303 | _If you want to send a post request to Roblox APIs with user credentials, add a `currentuser` header with the user name that you added to the config vars. Examples below._ 304 | 305 | Favorite the gear [Body Swap Potion](https://www.roblox.com/catalog/78730532/Body-Swap-Potion) (https://www.roblox.com/catalog/78730532/Body-Swap-Potion) using `User1` credentials 306 | 307 | ![Screen Shot 2564-11-14 at 7 39 20 AM](https://user-images.githubusercontent.com/46888825/141663409-00d0f9ee-48fc-4a64-a30f-cb5939eb948a.png) 308 | 309 | ```lua 310 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 311 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 312 | 313 | HttpProxy:PostAsync("https://catalog.roblox.com/v1/favorites/users/USER_ID_HERE/assets/78730532/favorite", true, nil, { 314 | currentuser = "User1" --Replace with the user you added in the config var (Case sensitive) 315 | }) 316 | ``` 317 | 318 | Favorite the gear [Body Swap Potion](https://www.roblox.com/catalog/78730532/Body-Swap-Potion) (https://www.roblox.com/catalog/78730532/Body-Swap-Potion) using `User2` credentials 319 | 320 | ![Screen Shot 2564-11-14 at 7 39 47 AM](https://user-images.githubusercontent.com/46888825/141663414-35492743-d1bc-4529-9ca3-939fe0274d09.png) 321 | 322 | ```lua 323 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 324 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 325 | 326 | HttpProxy:PostAsync("https://catalog.roblox.com/v1/favorites/users/USER_ID_HERE/assets/78730532/favorite", true, nil, { 327 | currentuser = "User2" --Replace with the user you added in the config var (Case sensitive) 328 | }) 329 | ``` 330 | 331 | _Replace USER_ID_HERE with your roblox account user id, see https://users.roblox.com//docs#!/Users/get_v1_users_authenticated_ 332 | 333 | See https://catalog.roblox.com/docs#!/Favorites/post_v1_favorites_users_userId_assets_assetId_favorite 334 | 335 | # HttpProxyService:PatchAsync 336 | 337 | **Parameters** 338 | 339 | | Name | Type | Default | Description | Required | 340 | | ------- | ----------------------------------------------------------------------------------------- | ------- | -------------------------------------------- | -------- | 341 | | url | [string](https://developer.roblox.com/en-us/articles/String) | | The web address you are requesting data from | true | 342 | | decode | [bool](https://developer.roblox.com/en-us/articles/Boolean) | true | Whether the request decodes the response | false | 343 | | data | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | The data being sent | false | 344 | | headers | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | Used to specify some HTTP request headers | false | 345 | 346 | **Returns** 347 | 348 | Result 349 | 350 | **Examples** 351 | 352 | _If you want to send a patch request to Roblox APIs with user credentials, add a `currentuser` header with the user name that you added to the config vars. Examples below._ 353 | 354 | Thumbs up the game [Crossroads](https://www.roblox.com/games/1818/Classic-Crossroads) (https://www.roblox.com/games/1818/Classic-Crossroads) using `User1` credentials 355 | 356 | ![Screen Shot 2564-11-14 at 7 39 20 AM](https://user-images.githubusercontent.com/46888825/141663409-00d0f9ee-48fc-4a64-a30f-cb5939eb948a.png) 357 | 358 | ```lua 359 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 360 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 361 | 362 | local UniverseId = HttpProxy:GetAsync("https://games.roblox.com/v1/games/multiget-place-details?placeIds=1818", true, { 363 | currentuser = "User1" --Replace with the user you added in the config var (Case sensitive) 364 | })[1].universeId --Get the game universe ID 365 | 366 | HttpProxy:PatchAsync("https://games.roblox.com/v1/games/" .. tostring(UniverseId) .. "/user-votes", true, { 367 | vote = true 368 | }, { 369 | currentuser = "User1" --Replace with the user you added in the config var (Case sensitive) 370 | }) --Thumbs up the game 371 | ``` 372 | 373 | Thumbs up the game [Crossroads](https://www.roblox.com/games/1818/Classic-Crossroads) (https://www.roblox.com/games/1818/Classic-Crossroads) using `User2` credentials 374 | 375 | ```lua 376 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 377 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 378 | 379 | local UniverseId = HttpProxy:GetAsync("https://games.roblox.com/v1/games/multiget-place-details?placeIds=1818", true, { 380 | currentuser = "User2" --Replace with the user you added in the config var (Case sensitive) 381 | })[1].universeId --Get the game universe ID 382 | 383 | HttpProxy:PatchAsync("https://games.roblox.com/v1/games/" .. tostring(UniverseId) .. "/user-votes", true, { 384 | vote = true 385 | }, { 386 | currentuser = "User2" --Replace with the user you added in the config var (Case sensitive) 387 | }) --Thumbs up the game 388 | ``` 389 | 390 | _For thumbs down, change `vote` to `false`._ 391 | 392 | See https://games.roblox.com//docs#!/Votes/patch_v1_games_universeId_user_votes 393 | 394 | # HttpProxyService:DeleteAsync 395 | 396 | **Parameters** 397 | 398 | | Name | Type | Default | Description | Required | 399 | | ------- | ----------------------------------------------------------------------------------------- | ------- | -------------------------------------------- | -------- | 400 | | url | [string](https://developer.roblox.com/en-us/articles/String) | | The web address you are requesting data from | true | 401 | | decode | [bool](https://developer.roblox.com/en-us/articles/Boolean) | true | Whether the request decodes the response | false | 402 | | headers | [dictionary](https://education.roblox.com/en-us/resources/intro-to-dictionaries---series) | {} | Used to specify some HTTP request headers | false | 403 | 404 | **Returns** 405 | 406 | Response Body 407 | 408 | **Examples** 409 | 410 | _If you want to send a delete request to Roblox APIs with user credentials, add a `currentuser` header with the user name that you added to the config vars. Examples below._ 411 | 412 | Unfavorite the gear [Body Swap Potion](https://www.roblox.com/catalog/78730532/Body-Swap-Potion) (https://www.roblox.com/catalog/78730532/Body-Swap-Potion) using `User1` credentials 413 | 414 | ![Screen Shot 2564-11-14 at 7 39 20 AM](https://user-images.githubusercontent.com/46888825/141663409-00d0f9ee-48fc-4a64-a30f-cb5939eb948a.png) 415 | 416 | ```lua 417 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 418 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 419 | 420 | HttpProxy:DeleteAsync("https://catalog.roblox.com/v1/favorites/users/USER_ID_HERE/assets/78730532/favorite", true, { 421 | currentuser = "User1" 422 | }) 423 | ``` 424 | 425 | Unfavorite the gear [Body Swap Potion](https://www.roblox.com/catalog/78730532/Body-Swap-Potion) (https://www.roblox.com/catalog/78730532/Body-Swap-Potion) using `User2` credentials 426 | 427 | ```lua 428 | local HttpProxyService = require(game:GetService("ServerStorage"):WaitForChild("HttpProxyService")) 429 | local HttpProxy = HttpProxyService:New(Password here) --Put your app password here 430 | 431 | HttpProxy:DeleteAsync("https://catalog.roblox.com/v1/favorites/users/USER_ID_HERE/assets/78730532/favorite", true, { 432 | currentuser = "User2" 433 | }) 434 | ``` 435 | 436 | _Replace USER_ID_HERE with your roblox account user id, see https://users.roblox.com//docs#!/Users/get_v1_users_authenticated_ 437 | 438 | See https://catalog.roblox.com/docs#!/Favorites/delete_v1_favorites_users_userId_assets_assetId_favorite 439 | 440 | # Updating 441 | 442 | **If you installed using recommended method** 443 | 444 | Open [GitHub](https://github.com) (https://github.com) 445 | ![Screen Shot 2564-11-13 at 11 52 07 AM](https://user-images.githubusercontent.com/46888825/141606102-5a1dc4a4-040c-4d2a-8918-85e219aea1e0.png) 446 | 447 | Click on your repository 448 | 449 | ![Screen Shot 2564-11-13 at 11 52 30 AM](https://user-images.githubusercontent.com/46888825/141606111-62177bb7-d252-40c3-9193-da3391100df9.png) 450 | 451 | If it says `This branch is x commits behind Unstable0:main`, it means there is an update. 452 | 453 | ![Screen Shot 2564-11-13 at 11 53 25 AM](https://user-images.githubusercontent.com/46888825/141606127-0e3b1328-3062-4e95-b88d-f1890805d147.png) 454 | 455 | Tp update, click on `Fetch Upstream` and click `Fetch and merge` 456 | 457 | ![Screen Shot 2564-11-13 at 11 54 19 AM](https://user-images.githubusercontent.com/46888825/141606153-7cf7284d-5c55-42ae-802a-8e5e66b6bd25.png) 458 | 459 | ![Screen Shot 2564-11-13 at 11 55 00 AM](https://user-images.githubusercontent.com/46888825/141606161-0bee1aa4-5075-470d-9387-5e3ec63c48bb.png) 460 | 461 | After you fetched the latest version, click [here](https://dashboard.heroku.com/apps) (https://dashboard.heroku.com/apps) to go to your [Heroku](https://www.heroku.com) account [dashboard](https://dashboard.heroku.com/apps) 462 | 463 | Click on your app 464 | 465 | ![Screen Shot 2564-11-13 at 11 56 30 AM](https://user-images.githubusercontent.com/46888825/141606204-42a6f873-99a3-466b-9f4c-b585c56d3f6a.png) 466 | 467 | Click `Deploy` 468 | 469 | ![Screen Shot 2564-11-13 at 11 57 19 AM](https://user-images.githubusercontent.com/46888825/141606219-c33bf599-3c8b-479c-ae5a-6ec9a11ccd01.png) 470 | 471 | Scroll down and click `Deploy Branch` to update. 472 | 473 | ![Screen Shot 2564-11-13 at 11 57 54 AM](https://user-images.githubusercontent.com/46888825/141606231-64dd3446-f570-4a8e-b190-2f444e3cf2fe.png) 474 | 475 | _Notes: You can enable automatic deployment so next time when you fetch the latest version on your repository, Heroku will re-deploy your app automatically (Meaning you do not need to re-deploy on your app dashboard)_ 476 | 477 | ![Screen Shot 2564-11-13 at 11 58 26 AM](https://user-images.githubusercontent.com/46888825/141606245-27017421-970e-4676-be08-8e573a45f47e.png) 478 | 479 | 518 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HttpProxyService", 3 | "description": "Send HTTP requests to Roblox APIs or Discord Webhooks in-game.", 4 | "repository": "https://github.com/Unstable0/HttpProxyService", 5 | "logo": "", 6 | "keywords": ["roblox-api", "roblox-proxy", "roblox-http-proxy"] 7 | } 8 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roblox-proxy", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "roblox-proxy", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "axios": "^1.2.1", 13 | "dotenv": "^16.0.3", 14 | "express": "^4.17.1" 15 | } 16 | }, 17 | "node_modules/accepts": { 18 | "version": "1.3.8", 19 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 20 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 21 | "dependencies": { 22 | "mime-types": "~2.1.34", 23 | "negotiator": "0.6.3" 24 | }, 25 | "engines": { 26 | "node": ">= 0.6" 27 | } 28 | }, 29 | "node_modules/array-flatten": { 30 | "version": "1.1.1", 31 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 32 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 33 | }, 34 | "node_modules/asynckit": { 35 | "version": "0.4.0", 36 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 37 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 38 | }, 39 | "node_modules/axios": { 40 | "version": "1.2.1", 41 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz", 42 | "integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==", 43 | "dependencies": { 44 | "follow-redirects": "^1.15.0", 45 | "form-data": "^4.0.0", 46 | "proxy-from-env": "^1.1.0" 47 | } 48 | }, 49 | "node_modules/body-parser": { 50 | "version": "1.20.1", 51 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 52 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 53 | "dependencies": { 54 | "bytes": "3.1.2", 55 | "content-type": "~1.0.4", 56 | "debug": "2.6.9", 57 | "depd": "2.0.0", 58 | "destroy": "1.2.0", 59 | "http-errors": "2.0.0", 60 | "iconv-lite": "0.4.24", 61 | "on-finished": "2.4.1", 62 | "qs": "6.11.0", 63 | "raw-body": "2.5.1", 64 | "type-is": "~1.6.18", 65 | "unpipe": "1.0.0" 66 | }, 67 | "engines": { 68 | "node": ">= 0.8", 69 | "npm": "1.2.8000 || >= 1.4.16" 70 | } 71 | }, 72 | "node_modules/bytes": { 73 | "version": "3.1.2", 74 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 75 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 76 | "engines": { 77 | "node": ">= 0.8" 78 | } 79 | }, 80 | "node_modules/call-bind": { 81 | "version": "1.0.2", 82 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 83 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 84 | "dependencies": { 85 | "function-bind": "^1.1.1", 86 | "get-intrinsic": "^1.0.2" 87 | }, 88 | "funding": { 89 | "url": "https://github.com/sponsors/ljharb" 90 | } 91 | }, 92 | "node_modules/combined-stream": { 93 | "version": "1.0.8", 94 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 95 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 96 | "dependencies": { 97 | "delayed-stream": "~1.0.0" 98 | }, 99 | "engines": { 100 | "node": ">= 0.8" 101 | } 102 | }, 103 | "node_modules/content-disposition": { 104 | "version": "0.5.4", 105 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 106 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 107 | "dependencies": { 108 | "safe-buffer": "5.2.1" 109 | }, 110 | "engines": { 111 | "node": ">= 0.6" 112 | } 113 | }, 114 | "node_modules/content-type": { 115 | "version": "1.0.4", 116 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 117 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 118 | "engines": { 119 | "node": ">= 0.6" 120 | } 121 | }, 122 | "node_modules/cookie": { 123 | "version": "0.5.0", 124 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 125 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 126 | "engines": { 127 | "node": ">= 0.6" 128 | } 129 | }, 130 | "node_modules/cookie-signature": { 131 | "version": "1.0.6", 132 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 133 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 134 | }, 135 | "node_modules/debug": { 136 | "version": "2.6.9", 137 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 138 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 139 | "dependencies": { 140 | "ms": "2.0.0" 141 | } 142 | }, 143 | "node_modules/delayed-stream": { 144 | "version": "1.0.0", 145 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 146 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 147 | "engines": { 148 | "node": ">=0.4.0" 149 | } 150 | }, 151 | "node_modules/depd": { 152 | "version": "2.0.0", 153 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 154 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 155 | "engines": { 156 | "node": ">= 0.8" 157 | } 158 | }, 159 | "node_modules/destroy": { 160 | "version": "1.2.0", 161 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 162 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 163 | "engines": { 164 | "node": ">= 0.8", 165 | "npm": "1.2.8000 || >= 1.4.16" 166 | } 167 | }, 168 | "node_modules/dotenv": { 169 | "version": "16.0.3", 170 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", 171 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", 172 | "engines": { 173 | "node": ">=12" 174 | } 175 | }, 176 | "node_modules/ee-first": { 177 | "version": "1.1.1", 178 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 179 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 180 | }, 181 | "node_modules/encodeurl": { 182 | "version": "1.0.2", 183 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 184 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 185 | "engines": { 186 | "node": ">= 0.8" 187 | } 188 | }, 189 | "node_modules/escape-html": { 190 | "version": "1.0.3", 191 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 192 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 193 | }, 194 | "node_modules/etag": { 195 | "version": "1.8.1", 196 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 197 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 198 | "engines": { 199 | "node": ">= 0.6" 200 | } 201 | }, 202 | "node_modules/express": { 203 | "version": "4.18.2", 204 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 205 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 206 | "dependencies": { 207 | "accepts": "~1.3.8", 208 | "array-flatten": "1.1.1", 209 | "body-parser": "1.20.1", 210 | "content-disposition": "0.5.4", 211 | "content-type": "~1.0.4", 212 | "cookie": "0.5.0", 213 | "cookie-signature": "1.0.6", 214 | "debug": "2.6.9", 215 | "depd": "2.0.0", 216 | "encodeurl": "~1.0.2", 217 | "escape-html": "~1.0.3", 218 | "etag": "~1.8.1", 219 | "finalhandler": "1.2.0", 220 | "fresh": "0.5.2", 221 | "http-errors": "2.0.0", 222 | "merge-descriptors": "1.0.1", 223 | "methods": "~1.1.2", 224 | "on-finished": "2.4.1", 225 | "parseurl": "~1.3.3", 226 | "path-to-regexp": "0.1.7", 227 | "proxy-addr": "~2.0.7", 228 | "qs": "6.11.0", 229 | "range-parser": "~1.2.1", 230 | "safe-buffer": "5.2.1", 231 | "send": "0.18.0", 232 | "serve-static": "1.15.0", 233 | "setprototypeof": "1.2.0", 234 | "statuses": "2.0.1", 235 | "type-is": "~1.6.18", 236 | "utils-merge": "1.0.1", 237 | "vary": "~1.1.2" 238 | }, 239 | "engines": { 240 | "node": ">= 0.10.0" 241 | } 242 | }, 243 | "node_modules/finalhandler": { 244 | "version": "1.2.0", 245 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 246 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 247 | "dependencies": { 248 | "debug": "2.6.9", 249 | "encodeurl": "~1.0.2", 250 | "escape-html": "~1.0.3", 251 | "on-finished": "2.4.1", 252 | "parseurl": "~1.3.3", 253 | "statuses": "2.0.1", 254 | "unpipe": "~1.0.0" 255 | }, 256 | "engines": { 257 | "node": ">= 0.8" 258 | } 259 | }, 260 | "node_modules/follow-redirects": { 261 | "version": "1.15.2", 262 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 263 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", 264 | "funding": [ 265 | { 266 | "type": "individual", 267 | "url": "https://github.com/sponsors/RubenVerborgh" 268 | } 269 | ], 270 | "engines": { 271 | "node": ">=4.0" 272 | }, 273 | "peerDependenciesMeta": { 274 | "debug": { 275 | "optional": true 276 | } 277 | } 278 | }, 279 | "node_modules/form-data": { 280 | "version": "4.0.0", 281 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 282 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 283 | "dependencies": { 284 | "asynckit": "^0.4.0", 285 | "combined-stream": "^1.0.8", 286 | "mime-types": "^2.1.12" 287 | }, 288 | "engines": { 289 | "node": ">= 6" 290 | } 291 | }, 292 | "node_modules/forwarded": { 293 | "version": "0.2.0", 294 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 295 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 296 | "engines": { 297 | "node": ">= 0.6" 298 | } 299 | }, 300 | "node_modules/fresh": { 301 | "version": "0.5.2", 302 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 303 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 304 | "engines": { 305 | "node": ">= 0.6" 306 | } 307 | }, 308 | "node_modules/function-bind": { 309 | "version": "1.1.1", 310 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 311 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 312 | }, 313 | "node_modules/get-intrinsic": { 314 | "version": "1.1.3", 315 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 316 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 317 | "dependencies": { 318 | "function-bind": "^1.1.1", 319 | "has": "^1.0.3", 320 | "has-symbols": "^1.0.3" 321 | }, 322 | "funding": { 323 | "url": "https://github.com/sponsors/ljharb" 324 | } 325 | }, 326 | "node_modules/has": { 327 | "version": "1.0.3", 328 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 329 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 330 | "dependencies": { 331 | "function-bind": "^1.1.1" 332 | }, 333 | "engines": { 334 | "node": ">= 0.4.0" 335 | } 336 | }, 337 | "node_modules/has-symbols": { 338 | "version": "1.0.3", 339 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 340 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 341 | "engines": { 342 | "node": ">= 0.4" 343 | }, 344 | "funding": { 345 | "url": "https://github.com/sponsors/ljharb" 346 | } 347 | }, 348 | "node_modules/http-errors": { 349 | "version": "2.0.0", 350 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 351 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 352 | "dependencies": { 353 | "depd": "2.0.0", 354 | "inherits": "2.0.4", 355 | "setprototypeof": "1.2.0", 356 | "statuses": "2.0.1", 357 | "toidentifier": "1.0.1" 358 | }, 359 | "engines": { 360 | "node": ">= 0.8" 361 | } 362 | }, 363 | "node_modules/iconv-lite": { 364 | "version": "0.4.24", 365 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 366 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 367 | "dependencies": { 368 | "safer-buffer": ">= 2.1.2 < 3" 369 | }, 370 | "engines": { 371 | "node": ">=0.10.0" 372 | } 373 | }, 374 | "node_modules/inherits": { 375 | "version": "2.0.4", 376 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 377 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 378 | }, 379 | "node_modules/ipaddr.js": { 380 | "version": "1.9.1", 381 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 382 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 383 | "engines": { 384 | "node": ">= 0.10" 385 | } 386 | }, 387 | "node_modules/media-typer": { 388 | "version": "0.3.0", 389 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 390 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 391 | "engines": { 392 | "node": ">= 0.6" 393 | } 394 | }, 395 | "node_modules/merge-descriptors": { 396 | "version": "1.0.1", 397 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 398 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 399 | }, 400 | "node_modules/methods": { 401 | "version": "1.1.2", 402 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 403 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 404 | "engines": { 405 | "node": ">= 0.6" 406 | } 407 | }, 408 | "node_modules/mime": { 409 | "version": "1.6.0", 410 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 411 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 412 | "bin": { 413 | "mime": "cli.js" 414 | }, 415 | "engines": { 416 | "node": ">=4" 417 | } 418 | }, 419 | "node_modules/mime-db": { 420 | "version": "1.52.0", 421 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 422 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 423 | "engines": { 424 | "node": ">= 0.6" 425 | } 426 | }, 427 | "node_modules/mime-types": { 428 | "version": "2.1.35", 429 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 430 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 431 | "dependencies": { 432 | "mime-db": "1.52.0" 433 | }, 434 | "engines": { 435 | "node": ">= 0.6" 436 | } 437 | }, 438 | "node_modules/ms": { 439 | "version": "2.0.0", 440 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 441 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 442 | }, 443 | "node_modules/negotiator": { 444 | "version": "0.6.3", 445 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 446 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 447 | "engines": { 448 | "node": ">= 0.6" 449 | } 450 | }, 451 | "node_modules/object-inspect": { 452 | "version": "1.12.2", 453 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 454 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 455 | "funding": { 456 | "url": "https://github.com/sponsors/ljharb" 457 | } 458 | }, 459 | "node_modules/on-finished": { 460 | "version": "2.4.1", 461 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 462 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 463 | "dependencies": { 464 | "ee-first": "1.1.1" 465 | }, 466 | "engines": { 467 | "node": ">= 0.8" 468 | } 469 | }, 470 | "node_modules/parseurl": { 471 | "version": "1.3.3", 472 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 473 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 474 | "engines": { 475 | "node": ">= 0.8" 476 | } 477 | }, 478 | "node_modules/path-to-regexp": { 479 | "version": "0.1.7", 480 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 481 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 482 | }, 483 | "node_modules/proxy-addr": { 484 | "version": "2.0.7", 485 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 486 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 487 | "dependencies": { 488 | "forwarded": "0.2.0", 489 | "ipaddr.js": "1.9.1" 490 | }, 491 | "engines": { 492 | "node": ">= 0.10" 493 | } 494 | }, 495 | "node_modules/proxy-from-env": { 496 | "version": "1.1.0", 497 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 498 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 499 | }, 500 | "node_modules/qs": { 501 | "version": "6.11.0", 502 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 503 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 504 | "dependencies": { 505 | "side-channel": "^1.0.4" 506 | }, 507 | "engines": { 508 | "node": ">=0.6" 509 | }, 510 | "funding": { 511 | "url": "https://github.com/sponsors/ljharb" 512 | } 513 | }, 514 | "node_modules/range-parser": { 515 | "version": "1.2.1", 516 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 517 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 518 | "engines": { 519 | "node": ">= 0.6" 520 | } 521 | }, 522 | "node_modules/raw-body": { 523 | "version": "2.5.1", 524 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 525 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 526 | "dependencies": { 527 | "bytes": "3.1.2", 528 | "http-errors": "2.0.0", 529 | "iconv-lite": "0.4.24", 530 | "unpipe": "1.0.0" 531 | }, 532 | "engines": { 533 | "node": ">= 0.8" 534 | } 535 | }, 536 | "node_modules/safe-buffer": { 537 | "version": "5.2.1", 538 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 539 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 540 | "funding": [ 541 | { 542 | "type": "github", 543 | "url": "https://github.com/sponsors/feross" 544 | }, 545 | { 546 | "type": "patreon", 547 | "url": "https://www.patreon.com/feross" 548 | }, 549 | { 550 | "type": "consulting", 551 | "url": "https://feross.org/support" 552 | } 553 | ] 554 | }, 555 | "node_modules/safer-buffer": { 556 | "version": "2.1.2", 557 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 558 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 559 | }, 560 | "node_modules/send": { 561 | "version": "0.18.0", 562 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 563 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 564 | "dependencies": { 565 | "debug": "2.6.9", 566 | "depd": "2.0.0", 567 | "destroy": "1.2.0", 568 | "encodeurl": "~1.0.2", 569 | "escape-html": "~1.0.3", 570 | "etag": "~1.8.1", 571 | "fresh": "0.5.2", 572 | "http-errors": "2.0.0", 573 | "mime": "1.6.0", 574 | "ms": "2.1.3", 575 | "on-finished": "2.4.1", 576 | "range-parser": "~1.2.1", 577 | "statuses": "2.0.1" 578 | }, 579 | "engines": { 580 | "node": ">= 0.8.0" 581 | } 582 | }, 583 | "node_modules/send/node_modules/ms": { 584 | "version": "2.1.3", 585 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 586 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 587 | }, 588 | "node_modules/serve-static": { 589 | "version": "1.15.0", 590 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 591 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 592 | "dependencies": { 593 | "encodeurl": "~1.0.2", 594 | "escape-html": "~1.0.3", 595 | "parseurl": "~1.3.3", 596 | "send": "0.18.0" 597 | }, 598 | "engines": { 599 | "node": ">= 0.8.0" 600 | } 601 | }, 602 | "node_modules/setprototypeof": { 603 | "version": "1.2.0", 604 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 605 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 606 | }, 607 | "node_modules/side-channel": { 608 | "version": "1.0.4", 609 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 610 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 611 | "dependencies": { 612 | "call-bind": "^1.0.0", 613 | "get-intrinsic": "^1.0.2", 614 | "object-inspect": "^1.9.0" 615 | }, 616 | "funding": { 617 | "url": "https://github.com/sponsors/ljharb" 618 | } 619 | }, 620 | "node_modules/statuses": { 621 | "version": "2.0.1", 622 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 623 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 624 | "engines": { 625 | "node": ">= 0.8" 626 | } 627 | }, 628 | "node_modules/toidentifier": { 629 | "version": "1.0.1", 630 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 631 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 632 | "engines": { 633 | "node": ">=0.6" 634 | } 635 | }, 636 | "node_modules/type-is": { 637 | "version": "1.6.18", 638 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 639 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 640 | "dependencies": { 641 | "media-typer": "0.3.0", 642 | "mime-types": "~2.1.24" 643 | }, 644 | "engines": { 645 | "node": ">= 0.6" 646 | } 647 | }, 648 | "node_modules/unpipe": { 649 | "version": "1.0.0", 650 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 651 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 652 | "engines": { 653 | "node": ">= 0.8" 654 | } 655 | }, 656 | "node_modules/utils-merge": { 657 | "version": "1.0.1", 658 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 659 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 660 | "engines": { 661 | "node": ">= 0.4.0" 662 | } 663 | }, 664 | "node_modules/vary": { 665 | "version": "1.1.2", 666 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 667 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 668 | "engines": { 669 | "node": ">= 0.8" 670 | } 671 | } 672 | } 673 | } 674 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roblox-proxy", 3 | "version": "1.0.0", 4 | "description": "Roblox Proxy.", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "engine": { 10 | "node": "17.1.0", 11 | "npm": "8.1.3" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/Unstable0/Roblox-Proxy.git" 16 | }, 17 | "keywords": [ 18 | "roblox-api", 19 | "roblox-proxy", 20 | "roblox-http-proxy" 21 | ], 22 | "author": "Unstable0", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/Unstable0/Roblox-Proxy/issues" 26 | }, 27 | "homepage": "https://github.com/Unstable0/Roblox-Proxy#readme", 28 | "dependencies": { 29 | "axios": "^1.2.1", 30 | "dotenv": "^16.0.3", 31 | "express": "^4.17.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | const axios = require("axios").default; 3 | const express = require("express"); 4 | const app = express(); 5 | 6 | const disallowedHeaders = ["host", "accept", "accept-encoding", "cache-control", "connection", "user-agent", "roblox-id", "currentuser"]; 7 | 8 | const tokens = {}; 9 | 10 | async function getNewToken(cookie) { 11 | try { 12 | await axios.post("https://auth.roblox.com/v2/logout", {}, { 13 | headers: { 14 | cookie: cookie 15 | } 16 | }); 17 | } catch (error) { 18 | if ("response" in error) { 19 | if (error.response.status !== 403) { 20 | return new Error("Invalid cookie"); 21 | }; 22 | 23 | return error.response.headers["x-csrf-token"]; 24 | } else { 25 | return new Error(error); 26 | }; 27 | }; 28 | }; 29 | 30 | async function getToken(cookie, newToken) { 31 | if (cookie in tokens) { 32 | if (newToken) { 33 | tokens[cookie] = await getNewToken(cookie); 34 | }; 35 | 36 | return tokens[cookie]; 37 | } else { 38 | tokens[cookie] = await getNewToken(cookie); 39 | 40 | return tokens[cookie]; 41 | }; 42 | }; 43 | 44 | function handleError(error, response) { 45 | if ("errors" in error.response.data) { 46 | if (error.response.data.errors[0] !== null) { 47 | return response.json({ 48 | error: { 49 | message: error.response.data.errors[0].message 50 | } 51 | }); 52 | }; 53 | } else if ("message" in error.response.data) { 54 | return response.json({ 55 | error: { 56 | message: error.response.data.message 57 | } 58 | }); 59 | }; 60 | 61 | response.json({ 62 | error: error 63 | }); 64 | }; 65 | 66 | app.use(express.urlencoded({ extended: true })); 67 | app.use(express.json()); 68 | 69 | app.post("/get", async (request, response) => { 70 | if (!request.query.url) { 71 | return response.json({ 72 | error: { 73 | message: "No URL Provided." 74 | } 75 | }); 76 | } else if (!request.query.password) { 77 | return response.json({ 78 | error: { 79 | message: "No Password Provided." 80 | } 81 | }); 82 | }; 83 | 84 | if (request.query.password !== process.env.password) { 85 | return response.json({ 86 | error: { 87 | message: "Invalid Password." 88 | } 89 | }); 90 | }; 91 | 92 | const headers = request.body; 93 | var newHeaders = {}; 94 | 95 | if ("currentuser" in headers) { 96 | if (headers.currentuser in process.env) { 97 | newHeaders.cookie = ".ROBLOSECURITY=" + process.env[headers.currentuser] 98 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, false); 99 | } else { 100 | return response.json({ 101 | error: { 102 | message: "Invalid user." 103 | } 104 | }); 105 | }; 106 | }; 107 | 108 | for (const [header, value] of Object.entries(headers)) { 109 | if (!disallowedHeaders.includes(header)) { 110 | newHeaders[header] = value; 111 | }; 112 | }; 113 | 114 | axios.get(request.query.url, { 115 | headers: newHeaders 116 | }) 117 | .then(function (response2) { 118 | response.json(response2.data); 119 | }) 120 | .catch(async function (error) { 121 | if (error.status === 403) { 122 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, true); 123 | 124 | axios.get(request.query.url, { 125 | headers: newHeaders 126 | }) 127 | .then(function (response2) { 128 | response.json(response2.data); 129 | }) 130 | .catch(function (error) { 131 | handleError(error, response); 132 | }); 133 | } else { 134 | handleError(error, response); 135 | }; 136 | }); 137 | }); 138 | 139 | app.post("/delete", async (request, response) => { 140 | if (!request.query.url) { 141 | return response.json({ 142 | error: { 143 | message: "No URL Provided." 144 | } 145 | }); 146 | } else if (!request.query.password) { 147 | return response.json({ 148 | error: { 149 | message: "No Password Provided." 150 | } 151 | }); 152 | }; 153 | 154 | if (request.query.password !== process.env.password) { 155 | return response.json({ 156 | error: { 157 | message: "Invalid Password." 158 | } 159 | }); 160 | }; 161 | 162 | const headers = request.body; 163 | var newHeaders = {}; 164 | 165 | if ("currentuser" in headers) { 166 | if (headers.currentuser in process.env) { 167 | newHeaders.cookie = ".ROBLOSECURITY=" + process.env[headers.currentuser] 168 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, false); 169 | } else { 170 | return response.json({ 171 | error: { 172 | message: "Invalid user." 173 | } 174 | }); 175 | }; 176 | }; 177 | 178 | for (const [header, value] of Object.entries(headers)) { 179 | if (!disallowedHeaders.includes(header)) { 180 | newHeaders[header] = value; 181 | }; 182 | }; 183 | 184 | axios.delete(request.query.url, { 185 | headers: newHeaders 186 | }) 187 | .then(function (response2) { 188 | response.json(response2.data); 189 | }) 190 | .catch(async function (error) { 191 | if (error.response.status === 403) { 192 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, true); 193 | 194 | axios.delete(request.query.url, { 195 | headers: newHeaders 196 | }) 197 | .then(function (response2) { 198 | response.json(response2.data); 199 | }) 200 | .catch(function (error) { 201 | handleError(error, response); 202 | }); 203 | } else { 204 | handleError(error, response); 205 | }; 206 | }); 207 | }); 208 | 209 | app.post("/post", async (request, response) => { 210 | if (!request.query.url) { 211 | return response.json({ 212 | error: { 213 | message: "No URL Provided." 214 | } 215 | }); 216 | } else if (!request.query.password) { 217 | return response.json({ 218 | error: { 219 | message: "No Password Provided." 220 | } 221 | }); 222 | }; 223 | 224 | if (request.query.password !== process.env.password) { 225 | return response.json({ 226 | error: { 227 | message: "Invalid Password." 228 | } 229 | }); 230 | }; 231 | 232 | const headers = request.body.Headers; 233 | var newHeaders = {}; 234 | 235 | if ("currentuser" in headers) { 236 | if (headers.currentuser in process.env) { 237 | newHeaders.cookie = ".ROBLOSECURITY=" + process.env[headers.currentuser] 238 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, false); 239 | } else { 240 | return response.json({ 241 | error: { 242 | message: "Invalid user." 243 | } 244 | }); 245 | }; 246 | }; 247 | 248 | for (const [header, value] of Object.entries(headers)) { 249 | if (!disallowedHeaders.includes(header)) { 250 | newHeaders[header] = value; 251 | }; 252 | }; 253 | 254 | axios.post(request.query.url, request.body.Data, { 255 | headers: newHeaders 256 | }) 257 | .then(function (response2) { 258 | response.json(response2.data); 259 | }) 260 | .catch(async function (error) { 261 | if (error.response.status === 403) { 262 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, true); 263 | 264 | axios.post(request.query.url, request.body.Data, { 265 | headers: newHeaders 266 | }) 267 | .then(function (response2) { 268 | response.json(response2.data); 269 | }) 270 | .catch(function (error) { 271 | handleError(error, response); 272 | }); 273 | } else { 274 | handleError(error, response); 275 | }; 276 | }); 277 | }); 278 | 279 | app.post("/patch", async (request, response) => { 280 | if (!request.query.url) { 281 | return response.json({ 282 | error: { 283 | message: "No URL Provided." 284 | } 285 | }); 286 | } else if (!request.query.password) { 287 | return response.json({ 288 | error: { 289 | message: "No Password Provided." 290 | } 291 | }); 292 | }; 293 | 294 | if (request.query.password !== process.env.password) { 295 | return response.json({ 296 | error: { 297 | message: "Invalid Password." 298 | } 299 | }); 300 | }; 301 | 302 | const headers = request.body.Headers; 303 | var newHeaders = {}; 304 | 305 | if ("currentuser" in headers) { 306 | if (headers.currentuser in process.env) { 307 | newHeaders.cookie = ".ROBLOSECURITY=" + process.env[headers.currentuser] 308 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, false); 309 | } else { 310 | return response.json({ 311 | error: { 312 | message: "Invalid user." 313 | } 314 | }); 315 | }; 316 | }; 317 | 318 | for (const [header, value] of Object.entries(headers)) { 319 | if (!disallowedHeaders.includes(header)) { 320 | newHeaders[header] = value; 321 | }; 322 | }; 323 | 324 | axios.patch(request.query.url, request.body.Data, { 325 | headers: newHeaders 326 | }) 327 | .then(function (response2) { 328 | response.json(response2.data); 329 | }) 330 | .catch(async function (error) { 331 | if (error.response.status === 403) { 332 | newHeaders["x-csrf-token"] = await getToken(newHeaders.cookie, true); 333 | 334 | axios.patch(request.query.url, request.body.Data, { 335 | headers: newHeaders 336 | }) 337 | .then(function (response2) { 338 | response.json(response2.data); 339 | }) 340 | .catch(function (error) { 341 | handleError(error, response); 342 | }); 343 | } else { 344 | handleError(error, response); 345 | }; 346 | }); 347 | }); 348 | 349 | app.listen(process.env.PORT || 80, () => { 350 | console.log(`Listening on port ${process.env.PORT || 80}`); 351 | }); --------------------------------------------------------------------------------