-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat(Hackviser): add activity #10579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+319
−0
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
7f08e4c
Add files via upload
efekrbas 7b498a9
Update metadata.json
efekrbas 9916b1d
Handle empty slug case in extractPageTitle function
efekrbas 10ea68e
Update presence.ts
efekrbas 2b5ee86
Update presence.ts
efekrbas 9bf1fa8
Fix formatting issue in metadata.json
efekrbas 43daea3
Update presence.ts
efekrbas f6c4919
Update presence.ts
efekrbas c4e8c9d
Update metadata.json
efekrbas e057b05
Update presence.ts
efekrbas e286237
Update metadata.json
efekrbas 09589b0
Update metadata.json
efekrbas 66c2f03
Update metadata.json
efekrbas e3022a1
Refactor extractPageTitle and getPageData functions
efekrbas ec41f2c
Delete websites/H/Hackviser/bg.jpg
efekrbas 4c096f8
Add files via upload
efekrbas a74f427
Merge branch 'main' into main
efekrbas 5bf3e14
Update presence.ts
efekrbas 8d5922a
Delete websites/H/Hackviser/bg.jpg
efekrbas 5724b39
Update metadata.json
efekrbas 8fdbeb6
Update presence.ts
efekrbas a00c784
Update presence.ts
efekrbas cf8b55a
Refactor presence data structure and comments
efekrbas 49781b3
Fix logo and thumbnail URLs in metadata.json
efekrbas 750bc98
Update metadata.json
efekrbas 20e780f
Delete websites/H/Hackviser/icon.png
efekrbas 7a62efb
Merge branch 'main' into main
efekrbas 1648036
Merge branch 'main' into main
efekrbas ddd6d1b
Merge branch 'main' into main
efekrbas a252a37
Merge branch 'main' into main
efekrbas 355a0e1
Update websites/H/Hackviser/metadata.json
efekrbas 364a809
Update metadata.json
efekrbas 5f3011f
Update presence.ts
efekrbas cf82ac3
Update presence.ts
efekrbas 3dd8b59
Update metadata.json
efekrbas 035aa54
Update presence.ts
efekrbas eb7ee2e
Update presence.ts
efekrbas 307959c
Change presenceData type to PresenceData
efekrbas 23c56e4
Merge branch 'main' into main
efekrbas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| { | ||
| "$schema": "https://schemas.premid.app/metadata/1.16", | ||
| "apiVersion": 1, | ||
| "author": { | ||
| "id": "378501743366897675", | ||
| "name": "hackviser" | ||
| }, | ||
| "service": "Hackviser", | ||
| "description": { | ||
| "en": "Hackviser is an online cybersecurity training platform where you can practice hacking skills through labs, CTF challenges, learning paths, and real-world scenarios.", | ||
| "tr": "Hackviser, laboratuvarlar, CTF yarışmaları, öğrenme yolları ve gerçek dünya senaryoları aracılığıyla siber güvenlik becerilerinizi geliştirebileceğiniz çevrimiçi bir eğitim platformudur." | ||
| }, | ||
| "url": "hackviser.com", | ||
| "regExp": "^https?[:][/][/]([a-zA-Z0-9-]+[.])*hackviser[.]com[/]", | ||
| "version": "1.0.0", | ||
| "logo": "https://i.ibb.co/ns57qq7g/512x512.jpg", | ||
| "thumbnail": "https://github.com/user-attachments/assets/bf3d8382-4789-494e-802a-244f571bf676?v=.png", | ||
| "color": "#00ff00", | ||
|
||
| "category": "other", | ||
|
||
| "tags": [ | ||
|
||
| "cybersecurity", | ||
| "hacking", | ||
| "ctf", | ||
| "labs", | ||
| "learning" | ||
| ] | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,292 @@ | ||
| const presence = new Presence({ | ||
| clientId: '1476565376513999030', | ||
| }) | ||
|
|
||
| let startTimestamp = Math.floor(Date.now() / 1000) | ||
| let lastPage = '' | ||
|
|
||
| /** | ||
| * Converts a URL slug into a human-readable title. | ||
| */ | ||
| function extractPageTitle(pathname: string): string | null { | ||
| const parts = pathname.split('/').filter(p => p.length > 0) | ||
| if (parts.length >= 2) { | ||
| const slug = parts[parts.length - 1] || '' | ||
| return slug | ||
|
||
| .replace(/[-_]/g, ' ') | ||
| .replace(/\b\w/g, l => l.toUpperCase()) | ||
| } | ||
| return null | ||
| } | ||
|
|
||
| /** | ||
| * Determines page info from the current pathname. | ||
| */ | ||
| function getPageData(pathname: string): { | ||
| page: string | ||
| details: string | ||
| state: string | ||
| sensitive: boolean | ||
| } { | ||
| // ── Auth pages (sensitive) ────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/login') | ||
| || pathname.startsWith('/register') | ||
| || pathname.startsWith('/forgot') | ||
| || pathname.startsWith('/reset') | ||
| ) { | ||
| return { | ||
| page: 'login', | ||
| details: 'Logging In', | ||
| state: '', | ||
| sensitive: true, | ||
| } | ||
| } | ||
|
|
||
| // ── Home ──────────────────────────────────────────────────── | ||
| if (pathname.startsWith('/home') || pathname === '/') { | ||
| return { | ||
| page: 'home', | ||
| details: 'Home Page', | ||
| state: 'Viewing Home Page', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Dashboard ─────────────────────────────────────────────── | ||
| if (pathname.startsWith('/dashboard')) { | ||
| return { | ||
| page: 'dashboard', | ||
| details: 'Dashboard', | ||
| state: 'Viewing Stats', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Academy ───────────────────────────────────────────────── | ||
| if (pathname.startsWith('/academy')) { | ||
| const subPage = extractPageTitle(pathname) | ||
| return { | ||
| page: 'academy', | ||
| details: 'Academy', | ||
| state: subPage || 'Browsing Categories', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Warmups ───────────────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/warmups') | ||
| || pathname.startsWith('/warmup') | ||
| ) { | ||
| const name = extractPageTitle(pathname) | ||
| return { | ||
| page: 'warmups', | ||
| details: 'Warmups', | ||
| state: name || 'Warming Up...', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Scenarios ─────────────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/scenarios') | ||
| || pathname.startsWith('/scenario') | ||
| ) { | ||
| const name = extractPageTitle(pathname) | ||
| return { | ||
| page: 'scenarios', | ||
| details: 'Scenarios', | ||
| state: name || 'Running Scenario', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Missions ──────────────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/missions') | ||
| || pathname.startsWith('/mission') | ||
| ) { | ||
| const name = extractPageTitle(pathname) | ||
| return { | ||
| page: 'missions', | ||
| details: 'Missions', | ||
| state: name || 'On a Mission', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Certifications ────────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/certifications') | ||
| || pathname.startsWith('/certification') | ||
| ) { | ||
| const name = extractPageTitle(pathname) | ||
| return { | ||
| page: 'certifications', | ||
| details: 'Certifications', | ||
| state: name || 'Viewing Certifications', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Labs / Machines ───────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/labs') | ||
| || pathname.startsWith('/lab') | ||
| || pathname.startsWith('/machines') | ||
| ) { | ||
| const labName = extractPageTitle(pathname) | ||
| return { | ||
| page: 'labs', | ||
| details: 'Solving Labs', | ||
| state: labName || 'Hacking in Progress...', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Support ───────────────────────────────────────────────── | ||
| if (pathname.startsWith('/support')) { | ||
| return { | ||
| page: 'support', | ||
| details: 'Support', | ||
| state: 'Getting Support', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Learning Paths / Courses ──────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/learning') | ||
| || pathname.startsWith('/paths') | ||
| || pathname.startsWith('/courses') | ||
| ) { | ||
| return { | ||
| page: 'learning', | ||
| details: 'Learning Paths', | ||
| state: 'Studying Cyber Security', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── CTF / Challenges ──────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/ctf') | ||
| || pathname.startsWith('/challenges') | ||
| ) { | ||
| return { | ||
| page: 'ctf', | ||
| details: 'CTF Challenge', | ||
| state: 'Capturing Flags', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Account Settings ──────────────────────────────────────── | ||
| if (pathname.startsWith('/account/settings')) { | ||
| return { | ||
| page: 'settings', | ||
| details: 'Settings', | ||
| state: 'A few changes', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Pricing Plans ─────────────────────────────────────────── | ||
| if (pathname.startsWith('/pricing-plans')) { | ||
| return { | ||
| page: 'pricing', | ||
| details: 'Pricing Plans', | ||
| state: 'Looking Pricing Plans', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── FAQ ───────────────────────────────────────────────────── | ||
| if (pathname.startsWith('/frequently-asked-questions')) { | ||
| return { | ||
| page: 'faq', | ||
| details: 'Frequently Asked Questions', | ||
| state: 'Looking for answers', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Profile / User ────────────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/profile') | ||
| || pathname.startsWith('/user') | ||
| || pathname.startsWith('/settings') | ||
| ) { | ||
| return { | ||
| page: 'profile', | ||
| details: 'Profile', | ||
| state: 'Viewing Profile', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Leaderboard / Rankings ────────────────────────────────── | ||
| if ( | ||
| pathname.startsWith('/leaderboard') | ||
| || pathname.startsWith('/scoreboard') | ||
| || pathname.startsWith('/ranking') | ||
| ) { | ||
| return { | ||
| page: 'leaderboard', | ||
| details: 'Leaderboard', | ||
| state: 'Checking Rankings', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Ticket ────────────────────────────────────────────────── | ||
| if (pathname.startsWith('/ticket')) { | ||
| return { | ||
| page: 'ticket', | ||
| details: 'Ticket', | ||
| state: 'Viewing Ticket', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Default: browsing ─────────────────────────────────────── | ||
| return { | ||
| page: 'browsing', | ||
| details: 'Browsing Platform', | ||
| state: '', | ||
| sensitive: false, | ||
| } | ||
| } | ||
|
|
||
| // ── Main update loop ──────────────────────────────────────────── | ||
| presence.on('UpdateData', async () => { | ||
| const pathname = document.location.pathname | ||
|
||
| const pageData = getPageData(pathname) | ||
|
|
||
| // Reset timer when the page changes | ||
| if (pageData.page !== lastPage) { | ||
| startTimestamp = Math.floor(Date.now() / 1000) | ||
| lastPage = pageData.page | ||
| } | ||
|
|
||
| const presenceData: PresenceData = { | ||
| startTimestamp, | ||
| largeImageKey: 'https://i.ibb.co/ns57qq7g/512x512.jpg', | ||
| } | ||
|
|
||
| // 265. Satır: ESLint Brace Style Düzeltmesi | ||
| if (pageData.sensitive) { | ||
| presenceData.details = pageData.details | ||
|
||
| } | ||
| else { | ||
| if (pageData.details) { | ||
| presenceData.details = pageData.details | ||
|
||
| } | ||
| if (pageData.state) { | ||
| presenceData.state = pageData.state | ||
|
||
| } | ||
| } | ||
|
|
||
| presence.setActivity(presenceData) | ||
|
||
| }) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.