@necrolab/dashboard 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +45 -0
- package/.eslintrc.js +24 -0
- package/.prettierignore +1 -0
- package/.prettierrc +10 -0
- package/.vscode/extensions.json +3 -0
- package/ICONS.md +21 -0
- package/README.md +65 -0
- package/backend/api.js +430 -0
- package/backend/auth.js +62 -0
- package/backend/batching.js +43 -0
- package/backend/endpoints.js +343 -0
- package/backend/index.js +23 -0
- package/backend/mock-data.js +66 -0
- package/backend/mock-src/classes/logger.js +112 -0
- package/backend/mock-src/classes/utils.js +42 -0
- package/backend/mock-src/ticketmaster.js +92 -0
- package/backend/validator.js +62 -0
- package/config/configs.json +20 -0
- package/config/filter.json +3 -0
- package/config/presale.csv +3 -0
- package/config/proxies.txt +6 -0
- package/config/used-codes.json +4 -0
- package/index.html +114 -0
- package/index.js +2 -0
- package/jsconfig.json +16 -0
- package/package.json +48 -0
- package/postcss.config.js +6 -0
- package/postinstall.js +9 -0
- package/public/android-chrome-192x192.png +0 -0
- package/public/android-chrome-512x512.png +0 -0
- package/public/apple-touch-icon.png +0 -0
- package/public/favicon-16x16.png +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/flags/ae.svg +1 -0
- package/public/flags/at.svg +1 -0
- package/public/flags/au.svg +1 -0
- package/public/flags/be.svg +1 -0
- package/public/flags/ch.svg +1 -0
- package/public/flags/cz.svg +1 -0
- package/public/flags/de.svg +1 -0
- package/public/flags/dk.svg +1 -0
- package/public/flags/es.svg +1 -0
- package/public/flags/nl.svg +1 -0
- package/public/flags/no.svg +1 -0
- package/public/flags/nz.svg +1 -0
- package/public/flags/pl.svg +1 -0
- package/public/flags/se.svg +1 -0
- package/public/flags/uk.svg +1 -0
- package/public/flags/us.svg +1 -0
- package/public/img/award.svg +3 -0
- package/public/img/background.svg +14 -0
- package/public/img/bag_w.svg +12 -0
- package/public/img/banks/amex.svg +4 -0
- package/public/img/banks/mastercard.svg +4 -0
- package/public/img/banks/visa.svg +4 -0
- package/public/img/camera.svg +3 -0
- package/public/img/close.svg +3 -0
- package/public/img/controls/disable.svg +5 -0
- package/public/img/controls/enable.svg +5 -0
- package/public/img/groups.svg +3 -0
- package/public/img/hand.svg +3 -0
- package/public/img/key.svg +3 -0
- package/public/img/logo.png +0 -0
- package/public/img/logo_icon.png +0 -0
- package/public/img/logo_icon_2.png +0 -0
- package/public/img/logo_trans.png +0 -0
- package/public/img/loyalty.svg +3 -0
- package/public/img/mail.svg +3 -0
- package/public/img/pencil.svg +3 -0
- package/public/img/profile.svg +4 -0
- package/public/img/reload.svg +3 -0
- package/public/img/sandclock.svg +25 -0
- package/public/img/save.svg +5 -0
- package/public/img/savings.svg +3 -0
- package/public/img/scanner.svg +3 -0
- package/public/img/sell.svg +3 -0
- package/public/img/shield.svg +3 -0
- package/public/img/ski.svg +3 -0
- package/public/img/stadium.svg +8 -0
- package/public/img/stadium_w.svg +8 -0
- package/public/img/timer.svg +3 -0
- package/public/manifest.json +27 -0
- package/public/robots.txt +2 -0
- package/run +10 -0
- package/src/App.vue +307 -0
- package/src/assets/css/_input.scss +197 -0
- package/src/assets/css/main.scss +269 -0
- package/src/assets/css/tailwind.css +3 -0
- package/src/assets/img/award.svg +3 -0
- package/src/assets/img/background.svg +11 -0
- package/src/assets/img/camera.svg +3 -0
- package/src/assets/img/close.svg +3 -0
- package/src/assets/img/eyes/closed.svg +13 -0
- package/src/assets/img/eyes/open.svg +12 -0
- package/src/assets/img/groups.svg +3 -0
- package/src/assets/img/hand.svg +3 -0
- package/src/assets/img/key.svg +3 -0
- package/src/assets/img/logo.png +0 -0
- package/src/assets/img/logo_icon.png +0 -0
- package/src/assets/img/logo_icon_2.png +0 -0
- package/src/assets/img/logo_trans.png +0 -0
- package/src/assets/img/loyalty.svg +3 -0
- package/src/assets/img/mail.svg +3 -0
- package/src/assets/img/pencil.svg +3 -0
- package/src/assets/img/reload.svg +3 -0
- package/src/assets/img/savings.svg +3 -0
- package/src/assets/img/scanner.svg +3 -0
- package/src/assets/img/sell.svg +3 -0
- package/src/assets/img/shield.svg +3 -0
- package/src/assets/img/ski.svg +3 -0
- package/src/assets/img/square_check.svg +5 -0
- package/src/assets/img/square_uncheck.svg +5 -0
- package/src/assets/img/stadium.svg +8 -0
- package/src/assets/img/timer.svg +3 -0
- package/src/assets/img/wildcard.svg +7 -0
- package/src/components/Auth/LoginForm.vue +48 -0
- package/src/components/Editors/Account/Account.vue +119 -0
- package/src/components/Editors/Account/AccountCreator.vue +147 -0
- package/src/components/Editors/Account/AccountView.vue +87 -0
- package/src/components/Editors/Account/CreateAccount.vue +106 -0
- package/src/components/Editors/Profile/CreateProfile.vue +321 -0
- package/src/components/Editors/Profile/Profile.vue +142 -0
- package/src/components/Editors/Profile/ProfileCountryChooser.vue +75 -0
- package/src/components/Editors/Profile/ProfileView.vue +96 -0
- package/src/components/Editors/TagLabel.vue +16 -0
- package/src/components/Editors/TagToggle.vue +41 -0
- package/src/components/Filter/Filter.vue +409 -0
- package/src/components/Filter/FilterPreview.vue +236 -0
- package/src/components/Filter/PriceSortToggle.vue +105 -0
- package/src/components/Table/Header.vue +5 -0
- package/src/components/Table/Row.vue +5 -0
- package/src/components/Table/Table.vue +14 -0
- package/src/components/Table/index.js +4 -0
- package/src/components/Tasks/CheckStock.vue +62 -0
- package/src/components/Tasks/Controls/DesktopControls.vue +73 -0
- package/src/components/Tasks/Controls/MobileControls.vue +32 -0
- package/src/components/Tasks/Controls/index.js +3 -0
- package/src/components/Tasks/CreateTaskAXS.vue +339 -0
- package/src/components/Tasks/CreateTaskTM.vue +459 -0
- package/src/components/Tasks/MassEdit.vue +50 -0
- package/src/components/Tasks/QuickSettings.vue +167 -0
- package/src/components/Tasks/ScrapeVenue.vue +42 -0
- package/src/components/Tasks/Stats.vue +66 -0
- package/src/components/Tasks/Task.vue +296 -0
- package/src/components/Tasks/TaskLabel.vue +20 -0
- package/src/components/Tasks/TaskView.vue +126 -0
- package/src/components/Tasks/Utilities.vue +33 -0
- package/src/components/icons/Award.vue +8 -0
- package/src/components/icons/Bag.vue +8 -0
- package/src/components/icons/BagWhite.vue +8 -0
- package/src/components/icons/Box.vue +8 -0
- package/src/components/icons/Camera.vue +8 -0
- package/src/components/icons/Cart.vue +8 -0
- package/src/components/icons/Check.vue +5 -0
- package/src/components/icons/Checkmark.vue +11 -0
- package/src/components/icons/Click.vue +8 -0
- package/src/components/icons/Close.vue +21 -0
- package/src/components/icons/CloseX.vue +5 -0
- package/src/components/icons/Console.vue +13 -0
- package/src/components/icons/Down.vue +8 -0
- package/src/components/icons/Edit.vue +13 -0
- package/src/components/icons/Event.vue +8 -0
- package/src/components/icons/Expand.vue +8 -0
- package/src/components/icons/Filter.vue +13 -0
- package/src/components/icons/Gear.vue +8 -0
- package/src/components/icons/Group.vue +8 -0
- package/src/components/icons/Hand.vue +8 -0
- package/src/components/icons/Key.vue +21 -0
- package/src/components/icons/Logout.vue +13 -0
- package/src/components/icons/Loyalty.vue +8 -0
- package/src/components/icons/Mail.vue +8 -0
- package/src/components/icons/Menu.vue +8 -0
- package/src/components/icons/Pause.vue +5 -0
- package/src/components/icons/Pencil.vue +21 -0
- package/src/components/icons/Play.vue +8 -0
- package/src/components/icons/Plus.vue +8 -0
- package/src/components/icons/Profile.vue +18 -0
- package/src/components/icons/Reload.vue +7 -0
- package/src/components/icons/Sandclock.vue +33 -0
- package/src/components/icons/Savings.vue +8 -0
- package/src/components/icons/Scanner.vue +8 -0
- package/src/components/icons/Scrape.vue +8 -0
- package/src/components/icons/Sell.vue +21 -0
- package/src/components/icons/Shield.vue +8 -0
- package/src/components/icons/Shrink.vue +8 -0
- package/src/components/icons/Ski.vue +8 -0
- package/src/components/icons/Spinner.vue +42 -0
- package/src/components/icons/SquareCheck.vue +18 -0
- package/src/components/icons/SquareUncheck.vue +18 -0
- package/src/components/icons/Stadium.vue +13 -0
- package/src/components/icons/StadiumWhite.vue +13 -0
- package/src/components/icons/Status.vue +8 -0
- package/src/components/icons/Tag.vue +8 -0
- package/src/components/icons/Tasks.vue +13 -0
- package/src/components/icons/Ticket.vue +8 -0
- package/src/components/icons/Timer.vue +8 -0
- package/src/components/icons/Trash.vue +8 -0
- package/src/components/icons/Up.vue +10 -0
- package/src/components/icons/Wildcard.vue +18 -0
- package/src/components/icons/index.js +111 -0
- package/src/components/ui/Modal.vue +61 -0
- package/src/components/ui/Navbar.vue +207 -0
- package/src/components/ui/ReconnectIndicator.vue +90 -0
- package/src/components/ui/Splash.vue +24 -0
- package/src/components/ui/controls/CountryChooser.vue +87 -0
- package/src/components/ui/controls/EyeToggle.vue +11 -0
- package/src/components/ui/controls/atomic/Checkbox.vue +28 -0
- package/src/components/ui/controls/atomic/Dropdown.vue +138 -0
- package/src/components/ui/controls/atomic/LoadingButton.vue +45 -0
- package/src/components/ui/controls/atomic/MultiDropdown.vue +262 -0
- package/src/components/ui/controls/atomic/Switch.vue +84 -0
- package/src/libs/Filter.js +593 -0
- package/src/libs/ansii.js +565 -0
- package/src/libs/panzoom.js +1413 -0
- package/src/main.js +23 -0
- package/src/registerServiceWorker.js +32 -0
- package/src/router/index.js +65 -0
- package/src/stores/cities.json +1 -0
- package/src/stores/connection.js +399 -0
- package/src/stores/countries.js +88 -0
- package/src/stores/logger.js +103 -0
- package/src/stores/requests.js +88 -0
- package/src/stores/sampleData.js +1034 -0
- package/src/stores/ui.js +584 -0
- package/src/stores/utils.js +554 -0
- package/src/types/index.js +42 -0
- package/src/utils/debug.js +1 -0
- package/src/views/Accounts.vue +191 -0
- package/src/views/Console.vue +224 -0
- package/src/views/Editor.vue +785 -0
- package/src/views/FilterBuilder.vue +785 -0
- package/src/views/Login.vue +27 -0
- package/src/views/Profiles.vue +209 -0
- package/src/views/Tasks.vue +157 -0
- package/static/offline.html +184 -0
- package/tailwind.config.js +57 -0
- package/vite.config.js +63 -0
- package/vue.config.js +32 -0
- package/workbox-config.js +66 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm run lint)",
|
|
5
|
+
"Bash(find:*)",
|
|
6
|
+
"Bash(ls:*)",
|
|
7
|
+
"Bash(grep:*)",
|
|
8
|
+
"Bash(npm run build:*)",
|
|
9
|
+
"Bash(npm view:*)",
|
|
10
|
+
"Bash(npm run dev:*)",
|
|
11
|
+
"Bash(sudo rm:*)",
|
|
12
|
+
"Bash(rm:*)",
|
|
13
|
+
"Bash(rg:*)",
|
|
14
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"const DEBUG\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/views/)",
|
|
15
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"border-2 border-dark-550\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
16
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"bg-dark-500\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
17
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"flex items-center justify-center\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
18
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"col-span.*flex.*items-center.*justify-center\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
19
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"button.*flex.*items-center.*justify-center.*gap\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
20
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"import.*useUIStore\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
21
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"const.*ref\\(\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
22
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"button-default.*bg-dark-400.*w-48.*text-xs.*flex.*items-center.*justify-center.*gap-x-2\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
23
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"const DEBUG.*window\\.location\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
24
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -A5 -B5 \"input-incrementer\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/components/Tasks/CreateTaskTM.vue)",
|
|
25
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -A2 -B2 \"label-override\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/assets/css/main.scss)",
|
|
26
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"MultiDropdown\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
27
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"ant-select.*multiple\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
28
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"multiple.*true\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
29
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"a-select\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
30
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"Select\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
31
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -A5 -B5 \"mode.*multiple\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/components/Tasks/)",
|
|
32
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -A10 -B5 \"a-select\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/components/Tasks/CreateTaskTM.vue)",
|
|
33
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"CountryChooser\\|currentCountry\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/views/Tasks.vue)",
|
|
34
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"currentModule\\|CountryChooser\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/components/ui/Navbar.vue)",
|
|
35
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -l \"CountryChooser\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/)",
|
|
36
|
+
"Bash(/opt/homebrew/lib/node_modules/@anthropic-ai/claude-code/vendor/ripgrep/arm64-darwin/rg -n \"bg-dark-400.*button\\|button.*bg-dark-400\" /Users/luca/Documents/GitHub/Necro/Dashboard/src/views/Tasks.vue)",
|
|
37
|
+
"Bash(npm install:*)",
|
|
38
|
+
"Bash(sudo chown:*)",
|
|
39
|
+
"Bash(sudo npm install:*)",
|
|
40
|
+
"Bash(node:*)",
|
|
41
|
+
"Bash(git checkout:*)"
|
|
42
|
+
],
|
|
43
|
+
"deny": []
|
|
44
|
+
}
|
|
45
|
+
}
|
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
browser: true,
|
|
4
|
+
es2021: true,
|
|
5
|
+
node: true
|
|
6
|
+
},
|
|
7
|
+
extends: ["eslint:recommended", "plugin:vue/vue3-essential"],
|
|
8
|
+
overrides: [],
|
|
9
|
+
parserOptions: {
|
|
10
|
+
ecmaVersion: "latest",
|
|
11
|
+
sourceType: "module"
|
|
12
|
+
},
|
|
13
|
+
plugins: ["vue"],
|
|
14
|
+
rules: {
|
|
15
|
+
"html.validate.scripts": 0,
|
|
16
|
+
"html.validate.styles": 0
|
|
17
|
+
},
|
|
18
|
+
ignorePatterns: ["src/registerServiceWorker.js", "src/libs/panzoom.js", "**/**.vue"],
|
|
19
|
+
globals: {
|
|
20
|
+
Bot: true,
|
|
21
|
+
refreshTaskOnFrontEnd: true,
|
|
22
|
+
pushWSUpdate: true
|
|
23
|
+
}
|
|
24
|
+
};
|
package/.prettierignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
src/components/editors/Profile/cities.json
|
package/.prettierrc
ADDED
package/ICONS.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Meanings of icons
|
|
2
|
+
|
|
3
|
+
-  `task.eventId`
|
|
4
|
+
-  `task.quantity`
|
|
5
|
+
-  `task.email`
|
|
6
|
+
-  `task.password`
|
|
7
|
+
-  `task.profileName` (this.profile?.profileName)
|
|
8
|
+
-  `task.proxy`
|
|
9
|
+
-  `task.smartTimer`
|
|
10
|
+
-  `task.loginAfterCart`
|
|
11
|
+
-  `task.manual`
|
|
12
|
+
-  `task.doNotPay`
|
|
13
|
+
-  `task.presaleMode`
|
|
14
|
+
-  `task.quickQueue`
|
|
15
|
+
-  `task.profileTag`
|
|
16
|
+
-  `task.accountTag`
|
|
17
|
+
-  `task.presaleCode`
|
|
18
|
+
-  `task.eventName`
|
|
19
|
+
-  `task.eventVenue`
|
|
20
|
+
-  `task.eventLocalDate`
|
|
21
|
+
-  `task.agedAccount`
|
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# 🎫 Necro Dashboard
|
|
2
|
+
|
|
3
|
+
A sophisticated PWA dashboard for managing ticket purchasing automation across multiple platforms. Built with Vue 3 and real-time WebSocket communication.
|
|
4
|
+
|
|
5
|
+
## ⚡ Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Visit `http://localhost:5173` and you're live.
|
|
13
|
+
|
|
14
|
+
## 🚀 Commands
|
|
15
|
+
|
|
16
|
+
| Command | Action |
|
|
17
|
+
| ---------------- | ----------------------------- |
|
|
18
|
+
| `npm run dev` | Development server |
|
|
19
|
+
| `npm run expose` | Network-accessible dev server |
|
|
20
|
+
| `npm run build` | Production build with PWA |
|
|
21
|
+
| `npm run lint` | Code formatting |
|
|
22
|
+
|
|
23
|
+
**Frontend Stack**
|
|
24
|
+
|
|
25
|
+
- Vue 3 + Composition API
|
|
26
|
+
- Pinia state management
|
|
27
|
+
- TailwindCSS + SCSS
|
|
28
|
+
- PWA with offline support
|
|
29
|
+
|
|
30
|
+
**Backend Stack**
|
|
31
|
+
|
|
32
|
+
- Express.js with WebSockets
|
|
33
|
+
- MessagePack serialization for big socket messages
|
|
34
|
+
- Real-time message batching
|
|
35
|
+
- Platform abstraction layer
|
|
36
|
+
|
|
37
|
+
## 📱 PWA Support
|
|
38
|
+
|
|
39
|
+
Built as a Progressive Web App with:
|
|
40
|
+
|
|
41
|
+
- 📲 Install to home screen
|
|
42
|
+
- 🔄 Background sync
|
|
43
|
+
- 📶 Offline functionality
|
|
44
|
+
- 🎨 Native app feel
|
|
45
|
+
|
|
46
|
+
## 🛠️ Development
|
|
47
|
+
|
|
48
|
+
The app runs in mock mode by default for development. Backend simulates bot operations while frontend provides full UI functionality.
|
|
49
|
+
|
|
50
|
+
**File Structure**
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
src/
|
|
54
|
+
├─ components/ # Reusable Vue components
|
|
55
|
+
├─ views/ # Page-level components
|
|
56
|
+
├─ stores/ # Pinia state management
|
|
57
|
+
└─ assets/ # Static resources
|
|
58
|
+
|
|
59
|
+
backend/
|
|
60
|
+
├─ api.js # Express server + WebSocket
|
|
61
|
+
├─ mock-data.js # Development data
|
|
62
|
+
└─ endpoints.js # API route definitions
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
package/backend/api.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
const enableWs = require("express-ws");
|
|
2
|
+
const express = require("express");
|
|
3
|
+
const cors = require("cors");
|
|
4
|
+
const cookieParser = require("cookie-parser");
|
|
5
|
+
const { encode } = require("@msgpack/msgpack");
|
|
6
|
+
const fs = require("node:fs");
|
|
7
|
+
const path = require("node:path");
|
|
8
|
+
|
|
9
|
+
const { createLogger } = require("./mock-src/classes/logger");
|
|
10
|
+
const utils = require("./mock-src/classes/utils");
|
|
11
|
+
|
|
12
|
+
const Batcher = require("./batching");
|
|
13
|
+
const endpoints = require("./endpoints");
|
|
14
|
+
const authSystem = require("./auth");
|
|
15
|
+
const { users } = require("./mock-data.js");
|
|
16
|
+
|
|
17
|
+
const logger = createLogger("WEB UI");
|
|
18
|
+
|
|
19
|
+
const maxWaitTime = 350; // ms
|
|
20
|
+
const maxMessageSize = 100;
|
|
21
|
+
|
|
22
|
+
const app = express();
|
|
23
|
+
const auth = new authSystem();
|
|
24
|
+
|
|
25
|
+
// CORS - for dev
|
|
26
|
+
const alowedCors = {
|
|
27
|
+
origin: ["*"]
|
|
28
|
+
};
|
|
29
|
+
app.use(cors(alowedCors));
|
|
30
|
+
// enable express-websocket
|
|
31
|
+
enableWs(app);
|
|
32
|
+
|
|
33
|
+
app.use((error, req, res, next) => {
|
|
34
|
+
logger.Error("Error Handling Middleware called");
|
|
35
|
+
logger.Error("Path: ", req.path);
|
|
36
|
+
next(); // (optional) invoking next middleware
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// serve static vue files
|
|
40
|
+
app.use(
|
|
41
|
+
express.static(path.join(__dirname, "../dist"), {
|
|
42
|
+
setHeaders: (res) => {
|
|
43
|
+
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// parse JSON
|
|
49
|
+
app.use(express.json());
|
|
50
|
+
// send and parse cookies
|
|
51
|
+
app.use(cookieParser());
|
|
52
|
+
|
|
53
|
+
// =======
|
|
54
|
+
// Config
|
|
55
|
+
// =======
|
|
56
|
+
|
|
57
|
+
const port = process.env.PORT || 8081;
|
|
58
|
+
const filesThatCanBeEdited = ["configs.json"];
|
|
59
|
+
|
|
60
|
+
global.refreshTaskOnFrontEnd = (task) => {
|
|
61
|
+
pushWSUpdate({
|
|
62
|
+
event: "task-update",
|
|
63
|
+
task: task,
|
|
64
|
+
id: task.taskId
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// =============
|
|
69
|
+
// Websocket
|
|
70
|
+
// =============
|
|
71
|
+
|
|
72
|
+
let wsClients = [];
|
|
73
|
+
|
|
74
|
+
const sendObject = (ws, batch) => {
|
|
75
|
+
// if object is too large, use msgpack encoding
|
|
76
|
+
const asString = JSON.stringify(batch);
|
|
77
|
+
if (asString.length > 1 && !Bot.Settings.DebugMode) return ws.send(encode(batch));
|
|
78
|
+
else return ws.send(asString);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const pushConsoleWSUpdate = (batch) => {
|
|
82
|
+
wsClients.forEach((c) => {
|
|
83
|
+
if (c.type !== "console") return;
|
|
84
|
+
batch = batch.filter((e) => !!e.log);
|
|
85
|
+
sendObject(c.ws, batch);
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const pushTaskWSUpdate = (batch) => {
|
|
90
|
+
wsClients.forEach((c) => {
|
|
91
|
+
if (c.type !== "tasks") return;
|
|
92
|
+
sendObject(c.ws, batch);
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const taskBatcher = new Batcher(pushTaskWSUpdate, maxMessageSize, maxWaitTime);
|
|
97
|
+
const logBatcher = new Batcher(pushConsoleWSUpdate, maxMessageSize, maxWaitTime);
|
|
98
|
+
|
|
99
|
+
const pushWSUpdate = (u) => {
|
|
100
|
+
if (u.type === "console") logBatcher.add(u);
|
|
101
|
+
else taskBatcher.add(u);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
global.pushWSUpdate = pushWSUpdate;
|
|
105
|
+
|
|
106
|
+
app.ws("/api/updates", async function (ws, req) {
|
|
107
|
+
let currentUser = users[0];
|
|
108
|
+
try {
|
|
109
|
+
// const acc = auth.validateAuthToken(req.cookies.auth);
|
|
110
|
+
// logger.Info(acc, req.cookies.auth);
|
|
111
|
+
// if (!acc.name) {
|
|
112
|
+
// ws.send('[{"event": "login"}]');
|
|
113
|
+
// return ws.close();
|
|
114
|
+
// }
|
|
115
|
+
ws.send(JSON.stringify([users[0]]));
|
|
116
|
+
} catch (e) {
|
|
117
|
+
logger.Error(e);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const id = utils.uuid();
|
|
122
|
+
|
|
123
|
+
logger.Info(`New websocket connected: ${id}`);
|
|
124
|
+
// Add client to array
|
|
125
|
+
|
|
126
|
+
wsClients.push({
|
|
127
|
+
ws: ws,
|
|
128
|
+
id: id,
|
|
129
|
+
type: req.query.type
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (req.query.type === "tasks") {
|
|
133
|
+
const send = (msg) => sendObject(ws, [msg]);
|
|
134
|
+
await utils.sleep(100);
|
|
135
|
+
pushWSUpdate({ event: "startup", message: "Starting Bot", user: currentUser.name });
|
|
136
|
+
await utils.sleep(750);
|
|
137
|
+
|
|
138
|
+
pushWSUpdate({ event: "startup", done: true, user: currentUser.name, version: "1.0" });
|
|
139
|
+
ws.send(
|
|
140
|
+
JSON.stringify([
|
|
141
|
+
{ event: "set-button-disabled", button: "add-tasks", value: false },
|
|
142
|
+
{ event: "set-button-disabled", button: "add-profiles", value: false },
|
|
143
|
+
{ event: "set-button-disabled", button: "add-accounts", value: false }
|
|
144
|
+
])
|
|
145
|
+
);
|
|
146
|
+
setTimeout(() => send({ event: "init-tasks", tasks: endpoints.getStrippedTasks(currentUser.name) }));
|
|
147
|
+
setTimeout(() => send({ event: "init-profiles", profiles: Bot.Profiles }));
|
|
148
|
+
setTimeout(() => send({ event: "init-tm-accounts", accounts: Bot.TM.Accounts }));
|
|
149
|
+
setTimeout(() => send({ event: "init-axs-accounts", accounts: Bot.AXS.Accounts }));
|
|
150
|
+
|
|
151
|
+
ws.on("message", async (msg) => {
|
|
152
|
+
if (msg === "ping") return ws.send("pong");
|
|
153
|
+
const parsed = JSON.parse(msg);
|
|
154
|
+
parsed.data.user = currentUser;
|
|
155
|
+
const res = await endpoints.handleWebsocketMessage(parsed);
|
|
156
|
+
if (res?.error) ws.send(JSON.stringify([{ event: "error", msg: res.error }]));
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
if (req.query.type === "console") {
|
|
160
|
+
for (let c = 0; c < Bot.ConsoleBuffer.length; c++) {
|
|
161
|
+
pushWSUpdate({
|
|
162
|
+
type: "console",
|
|
163
|
+
...Bot.ConsoleBuffer[c]
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
ws.on("close", () => {
|
|
169
|
+
logger.Yellow("WebSocket was closed:", id);
|
|
170
|
+
// Remove client from array
|
|
171
|
+
wsClients = wsClients.filter((c) => c.id !== id);
|
|
172
|
+
});
|
|
173
|
+
} catch (e) {
|
|
174
|
+
logger.Error(e);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// catches vue reloads
|
|
179
|
+
app.use(
|
|
180
|
+
["/login", "/console", "/editor", "/filter", "/profiles", "/accounts"],
|
|
181
|
+
express.static(path.join(__dirname, "../dist/index.html"))
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// ==============
|
|
185
|
+
// API endpoints
|
|
186
|
+
// ==============
|
|
187
|
+
|
|
188
|
+
// ===== Login ======
|
|
189
|
+
app.post("/api/login", async (req, res) => {
|
|
190
|
+
const pwd = req.body.password;
|
|
191
|
+
const user = req.body.name;
|
|
192
|
+
const authResult = auth.loginToAccount(user, pwd);
|
|
193
|
+
if (authResult.token) return res.cookie("auth", authResult.token).send(authResult);
|
|
194
|
+
else return res.send(authResult);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
app.post("/api/logout", async (req, res) => {
|
|
198
|
+
const token = req.cookies.auth;
|
|
199
|
+
const result = auth.invalidateAuthToken(token);
|
|
200
|
+
return res.cookie("auth", "").send(result);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// ===== File editing =====
|
|
204
|
+
|
|
205
|
+
// Get list of all the available files
|
|
206
|
+
app.get("/api/json-files", async (req, res) => {
|
|
207
|
+
res.send(filesThatCanBeEdited);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Get current content of one of the files
|
|
211
|
+
app.get("/api/json-file", async (req, res) => {
|
|
212
|
+
const requestedFile = req.query.file;
|
|
213
|
+
if (!requestedFile)
|
|
214
|
+
return res.status(400).send({
|
|
215
|
+
error: "No file specified: missing ?file= parameter"
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (!filesThatCanBeEdited.includes(requestedFile))
|
|
219
|
+
return res.status(400).send({
|
|
220
|
+
error: "File can't be edited: check /api/json-files"
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const content = fs.readFileSync(path.normalize(`${process.cwd()}/config/${requestedFile}`), "utf8");
|
|
224
|
+
return res.send({
|
|
225
|
+
content: utils.btoa(content)
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Set new content of one of the files
|
|
230
|
+
app.post("/api/json-file", async (req, res) => {
|
|
231
|
+
const requestedFile = req.query.file;
|
|
232
|
+
if (!requestedFile)
|
|
233
|
+
return res.status(400).send({
|
|
234
|
+
error: "No file specified: missing ?file= parameter"
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
if (!filesThatCanBeEdited.includes(requestedFile))
|
|
238
|
+
return res.status(400).send({
|
|
239
|
+
error: "File can't be edited: check /api/json-files"
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const content = utils.atob(req.body.content);
|
|
243
|
+
|
|
244
|
+
if (!content)
|
|
245
|
+
return res.status(400).send({
|
|
246
|
+
error: "Request must contain a content field"
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
if (requestedFile.endsWith(".json")) JSON.parse(content);
|
|
251
|
+
} catch (e) {
|
|
252
|
+
return res.status(400).send({
|
|
253
|
+
error: "Content must be valid JSON"
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
fs.writeFile(path.normalize(`${process.cwd()}/config/${requestedFile}`), content, (err) => {
|
|
258
|
+
if (err) {
|
|
259
|
+
console.error(err);
|
|
260
|
+
return res.status(400).send({
|
|
261
|
+
error: err
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return res.send({});
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const closeTab = (res) => {
|
|
269
|
+
res.set("Content-Type", "text/html");
|
|
270
|
+
res.send(Buffer.from("<script>window.close();</script>"));
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// ===== Task managing =====
|
|
274
|
+
|
|
275
|
+
// ===== Continue task (manual) =====
|
|
276
|
+
app.get("/api/tasks/continue", async (req, res) => {
|
|
277
|
+
const r = await endpoints.continueTask(req.query);
|
|
278
|
+
if (r.error) return res.send(r);
|
|
279
|
+
else closeTab(res);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// ===== Open Browser =====
|
|
283
|
+
app.get("/api/tasks/delete", async (req, res) => {
|
|
284
|
+
const r = await endpoints.deleteTask(req.query);
|
|
285
|
+
if (r.error) return res.send(r);
|
|
286
|
+
else closeTab(res);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Get all tasks
|
|
290
|
+
app.get("/api/tasks", async (req, res) => {
|
|
291
|
+
return res.send(await endpoints.getTasks());
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
app.get("/api/tasks/load-presale", async (req, res) => {
|
|
295
|
+
await endpoints.deleteAllTasks();
|
|
296
|
+
closeTab(res);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
app.get("/api/tasks/start", async (req, res) => {
|
|
300
|
+
return res.send(await endpoints.startTask(req.query));
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
app.get("/api/tasks/stop", async (req, res) => {
|
|
304
|
+
return res.send(await endpoints.stopTask(req.query));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
app.post("/api/tasks/add", async (req, res) => {
|
|
308
|
+
return res.send(await endpoints.addTask(req.body));
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
app.post("/api/mass-edit-presale-code", async (req, res) => {
|
|
312
|
+
return res.send(await endpoints.massEditPresaleCode(req.body));
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
app.post("/api/scrape-map", async (req, res) => {
|
|
316
|
+
return res.send(await endpoints.scrapeMap(req.body));
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
app.post("/api/check-stock", async (req, res) => {
|
|
320
|
+
return res.send(await endpoints.checkStock(req.body));
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
let filter = {};
|
|
324
|
+
app.get("/api/filter/load", async (req, res) => {
|
|
325
|
+
res.json({
|
|
326
|
+
filters: [
|
|
327
|
+
{ eventId: "542695", generalAdmission: true },
|
|
328
|
+
{ eventId: "542695", buyAny: true },
|
|
329
|
+
{ eventId: "529171", section: "INNENRAUM STEHPLATZ" }
|
|
330
|
+
],
|
|
331
|
+
globalFilter: { priceSort: "desc", minPrice: 0, maxPrice: 0 }
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
app.post("/api/filter/save", async (req, res) => {
|
|
336
|
+
filter = req.body;
|
|
337
|
+
logger.Info("Saved filter", filter);
|
|
338
|
+
res.json(filter);
|
|
339
|
+
});
|
|
340
|
+
app.get("/api/cors", async (req, res) => {
|
|
341
|
+
const { url } = req.query;
|
|
342
|
+
if (!url) {
|
|
343
|
+
return res.status(400).send({ error: "No URL provided" });
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
const response = await fetch(url);
|
|
348
|
+
|
|
349
|
+
if (!response.ok) {
|
|
350
|
+
return res.status(response.status).send({
|
|
351
|
+
error: `Upstream server returned ${response.status}`
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const contentType = response.headers.get("content-type") || "application/octet-stream";
|
|
356
|
+
const data = Buffer.from(await response.arrayBuffer());
|
|
357
|
+
|
|
358
|
+
if (contentType.includes("application/json")) {
|
|
359
|
+
const jsonData = JSON.parse(data.toString());
|
|
360
|
+
return res.type(contentType).send(jsonData);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
res.type(contentType).send(data);
|
|
364
|
+
|
|
365
|
+
logger.Info("Proxied", url, response.status);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
logger.Error("Proxy error", { url, error: error.message });
|
|
368
|
+
res.status(500).send({ error: error.message });
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
// ===== Reload proxies / profiles =====
|
|
373
|
+
|
|
374
|
+
let config = {};
|
|
375
|
+
app.get("/api/quickconfig", async (req, res) => {
|
|
376
|
+
return res.json({
|
|
377
|
+
keys: {
|
|
378
|
+
Captcha: {
|
|
379
|
+
CapMonster: "example",
|
|
380
|
+
CapSolver: "example",
|
|
381
|
+
Invizible: "example",
|
|
382
|
+
TwoCaptcha: "example"
|
|
383
|
+
},
|
|
384
|
+
SMS: {
|
|
385
|
+
Quackr: "example",
|
|
386
|
+
SMSActivate: "example"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
app.post("/api/quickconfig", async (req, res) => {
|
|
393
|
+
config = JSON.parse(atob(req.body.content));
|
|
394
|
+
return res.json(config);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
let proxies;
|
|
398
|
+
app.get("/api/proxies", async (req, res) => {
|
|
399
|
+
return res.send(proxies);
|
|
400
|
+
});
|
|
401
|
+
app.post("/api/proxies", async (req, res) => {
|
|
402
|
+
proxies = atob(req.body.content);
|
|
403
|
+
res.send(proxies);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
app.post("/api/userconfig/set", async (req, res) => {
|
|
407
|
+
// eslint-disable-next-line no-unused-vars
|
|
408
|
+
const { field, value } = req.body;
|
|
409
|
+
|
|
410
|
+
users[0].proxyList = value;
|
|
411
|
+
|
|
412
|
+
return res.send(users[0]);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
app.get("/api/userconfig/proxylists", async (req, res) => {
|
|
416
|
+
return res.send(["admin-proxies", "admin-proxies-1", "admin-proxies-2"]);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
app.get("/api/userconfig/balances", async (req, res) => {
|
|
420
|
+
return res.send({ CapSolver: 100, TwoCaptcha: 40 });
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
module.exports = {
|
|
424
|
+
start: async () => {
|
|
425
|
+
// onChange = (await import('on-change')).default;
|
|
426
|
+
app.listen(port, "0.0.0.0", () => {
|
|
427
|
+
logger.Info("Web API started on port:", port);
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
};
|
package/backend/auth.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const crypto = require("node:crypto");
|
|
2
|
+
|
|
3
|
+
const generateAuthToken = () => {
|
|
4
|
+
return crypto.randomUUID();
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// This is not secure, at all.
|
|
8
|
+
// If you need it to be more secure, at least
|
|
9
|
+
// use some kind of hashing for passwords
|
|
10
|
+
|
|
11
|
+
// ===============
|
|
12
|
+
// Auth middleware
|
|
13
|
+
// ===============
|
|
14
|
+
let currentAuthTokens = {};
|
|
15
|
+
|
|
16
|
+
class Auth {
|
|
17
|
+
registerNewAccount(name, password) {
|
|
18
|
+
Bot.Users.push({
|
|
19
|
+
name: name,
|
|
20
|
+
password: password
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
loginToAccount(name, password) {
|
|
24
|
+
let res = null;
|
|
25
|
+
Bot.Users.forEach((acc) => {
|
|
26
|
+
if (acc.name === name && acc.password === password) res = acc;
|
|
27
|
+
});
|
|
28
|
+
if (!res || !res?.name)
|
|
29
|
+
return {
|
|
30
|
+
error: "name or password incorrect",
|
|
31
|
+
token: null
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const auth = generateAuthToken();
|
|
35
|
+
currentAuthTokens[auth] = res;
|
|
36
|
+
return {
|
|
37
|
+
error: null,
|
|
38
|
+
token: auth,
|
|
39
|
+
profile: {
|
|
40
|
+
name: res.name,
|
|
41
|
+
profilePicture: res.profilePicture
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
invalidateAuthToken(token) {
|
|
46
|
+
if (!currentAuthTokens[token])
|
|
47
|
+
return {
|
|
48
|
+
error: "Token does not exist"
|
|
49
|
+
};
|
|
50
|
+
delete currentAuthTokens[token];
|
|
51
|
+
return {};
|
|
52
|
+
}
|
|
53
|
+
validateAuthToken(token) {
|
|
54
|
+
if (!currentAuthTokens[token])
|
|
55
|
+
return {
|
|
56
|
+
error: "Token does not exist"
|
|
57
|
+
};
|
|
58
|
+
return currentAuthTokens[token];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = Auth;
|