Skip to content

Commit

Permalink
2.8 - Lunar
Browse files Browse the repository at this point in the history
  • Loading branch information
ManucrackYT committed Jul 1, 2024
1 parent 3d1c0ed commit ef1a427
Show file tree
Hide file tree
Showing 36 changed files with 726 additions and 655 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version": "2.7"}
{"version": "2.8"}
19 changes: 4 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<p align="center"><img src="/assets/img/logo_background.png" width="150px" height="150px" alt="logo"></p>
<p align="center"><img src="https://cdn.discordapp.com/attachments/1190680696524652654/1197981100140658790/logo_background.png?ex=65bd3dd7&is=65aac8d7&hm=c35b4d7db24937198bdc99cf1a14299d5bc81298f1cb9f988ce87a0d9ff6fa03&" width="150px" height="150px" alt="logo"></p>

<h1 align="center">Lapsus Client</h1>


<p align="center">Lapsus Client, the most modern and customizable Pterodactyl Client Area for your hosting.</p>

![Login Page](/assets/img/login_page.png)
![Login Page](https://cdn.discordapp.com/attachments/1190680696524652654/1197981520376385596/login_page.png?ex=65bd3e3b&is=65aac93b&hm=227cecf95a7a435e775eb9b3799bc0d16d70021036e3c81e24ddba3abbbde78f&)

## Features

* 🖌️ Customizable Client Area.
* Change easily name and logo
* Customize news as you want, modify the news title, picture, description and link
* Customize news as you want, modify the new title, picture, description and link
* 📂 See your servers, all in one place.
* See which servers you have created on the Dashboard and access them by clicking just a button
* 🔑 **Discord Authentication.**
Expand All @@ -23,18 +23,6 @@

This is not an exhaustive list. Download and setup the client to see what you can do!

## Using the installation scripts

An easy way to install Lapsus Client is by using our script, simply run this command as root. The script will do everything for you.
**Before using the script, check you have
a supported NodeJS version installed on your system**

```bash
bash <(curl -s https://script.lapsusdev.tech)
```

_Note: On some systems, it's required to be already logged in as root before executing the one-line command (where `sudo` is in front of the command does not work)._


#### Like the project? Leave a ⭐ star on the repository!

Expand Down Expand Up @@ -74,6 +62,7 @@ The best way to contact the developers is on Discord.

---

### See you.


[nodejs]: https://nodejs.org/en/ 'Node.js'
Expand Down
162 changes: 162 additions & 0 deletions api/linkvertise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
const settings = require('../settings.json')

module.exports.load = async function (app, db) {

const lvcodes = {}
const cooldowns = {}

app.get(`/lv/gen`, async (req, res) => {
if (!req.session.pterodactyl) return res.redirect("/login");

if (cooldowns[req.session.userinfo.id] && cooldowns[req.session.userinfo.id] > Date.now()) {
return res.redirect(`/lv`)
} else if (cooldowns[req.session.userinfo.id]) {
delete cooldowns[req.session.userinfo.id]
}

const dailyTotal = await db.get(`dailylinkvertise-${req.session.userinfo.id}`)
if (dailyTotal && dailyTotal >= settings.linkvertise.dailyLimit) {
return res.redirect(`/lv?err=REACHEDDAILYLIMIT`)
}

let referer = req.headers.referer
if (!referer) return res.send('An error occured with your browser!')
referer = referer.toLowerCase()
if (referer.includes('?')) referer = referer.split('?')[0]
if (!referer.endsWith(`/lv`) && !referer.endsWith(`/lv/`)) return res.send('An error occured with your browser!')
if (!referer.endsWith(`/`)) referer += `/`

const code = makeid(12)
const lvurl = linkvertise(settings.linkvertise.userid, referer + `redeem/${code}`)

lvcodes[req.session.userinfo.id] = {
code: code,
user: req.session.userinfo.id,
generated: Date.now()
}

res.redirect(lvurl)
})

app.get(`/lv/redeem/:code`, async (req, res) => {
if (!req.session.pterodactyl) return res.redirect("/");

if (cooldowns[req.session.userinfo.id] && cooldowns[req.session.userinfo.id] > Date.now()) {
return res.redirect(`/lv`)
} else if (cooldowns[req.session.userinfo.id]) {
delete cooldowns[req.session.userinfo.id]
}


const code = req.params.code
if (!code) return res.send('An error occured with your browser!')
if (!req.headers.referer || !req.headers.referer.includes('linkvertise.com')) return res.send('<p>Hmm... our systems detected something weird! Please make sure you are not using an ad blocker or a linkvertise bypasser.</p> <img src="https://tr.rbxcdn.com/997776fdf5a04f499ccd2b753ea605c3/420/420/Hat/Webp" alt="cat" height="600">')

const usercode = lvcodes[req.session.userinfo.id]
if (!usercode) return res.redirect(`/lv`)
if (usercode.code !== code) return res.redirect(`/lv`)
delete lvcodes[req.session.userinfo.id]

// Checking at least the minimum allowed time passed between generation and completion
if (((Date.now() - usercode.generated) / 1000) < settings.linkvertise.minTimeToComplete) {
return res.send('<p>Hmm... our systems detected something weird! Please make sure you are not using an ad blocker or a linkvertise bypasser. <a href="/lv">Generate another link</a></p> <img src="https://tr.rbxcdn.com/997776fdf5a04f499ccd2b753ea605c3/420/420/Hat/Webp" alt="cat" height="600">')
}

cooldowns[req.session.userinfo.id] = Date.now() + (settings.linkvertise.cooldown * 1000)

// Adding to daily total
const dailyTotal = await db.get(`dailylinkvertise-${req.session.userinfo.id}`)
if (dailyTotal && dailyTotal >= settings.linkvertise.dailyLimit) {
return res.redirect(`/lv?err=REACHEDDAILYLIMIT`)
}
if (dailyTotal) await db.set(`dailylinkvertise-${req.session.userinfo.id}`, dailyTotal + 1)
else await db.set(`dailylinkvertise-${req.session.userinfo.id}`, 1)
if (dailyTotal + 1 >= settings.linkvertise.dailyLimit) {
await db.set(`lvlimitdate-${req.session.userinfo.id}`, Date.now(), 43200000)
}

// Adding coins
const coins = await db.get(`coins-${req.session.userinfo.id}`)
await db.set(`coins-${req.session.userinfo.id}`, coins + settings.linkvertise.coins)

res.redirect(`/lv?success=true`)
})

app.get(`/api/lvcooldown`, async (req, res) => {
if (!req.session.pterodactyl) return res.json({ error: true, message: 'Not logged in' })

const limitTimestamp = await db.get(`lvlimitdate-${req.session.userinfo.id}`)
if (limitTimestamp) {
if ((limitTimestamp + 43200000) < Date.now()) {
db.delete(`dailylinkvertise-${req.session.userinfo.id}`)
await db.delete(`lvlimitdate-${req.session.userinfo.id}`)
} else {
return res.json({ dailyLimit: true, readable: msToHoursAndMinutes((limitTimestamp + 43200000) - Date.now()) })
}
}

if (cooldowns[req.session.userinfo.id] && cooldowns[req.session.userinfo.id] < Date.now()) {
delete cooldowns[req.session.userinfo.id]
}

return res.json({ cooldown: cooldowns[req.session.userinfo.id] ?? null })
})

// Removing codes that have expired and cooldowns that are no longer applicable
setInterval(() => {
for (const code of Object.values(lvcodes)) {
if (((Date.now() - code.generated) / 1000) > settings.linkvertise.timeToExpire) {
delete lvcodes[code.user]
}
}

for (const user of Object.keys(cooldowns)) {
const cooldown = cooldowns[user]
if (cooldown < Date.now()) delete cooldowns[user]
}
}, 10000)

}

function linkvertise(userid, link) {
var base_url = `https://link-to.net/${userid}/${Math.random() * 1000}/dynamic`;
var href = base_url + "?r=" + btoa(encodeURI(link));
return href;
}

function btoa(str) {
var buffer;

if (str instanceof Buffer) {
buffer = str;
} else {
buffer = Buffer.from(str.toString(), "binary");
}
return buffer.toString("base64");
}

function makeid(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let result = Array.from({ length }, () => characters.charAt(Math.floor(Math.random() * charactersLength))).join('');
return result;
}

function msToHoursAndMinutes(ms) {
const msInHour = 3600000
const msInMinute = 60000

const hours = Math.floor(ms / msInHour)
const minutes = Math.round((ms - (hours * msInHour)) / msInMinute * 100) / 100

let pluralHours = `s`
if (hours === 1) {
pluralHours = ``
}
let pluralMinutes = `s`
if (minutes === 1) {
pluralMinutes = ``
}

return `${hours} hour${pluralHours} and ${minutes} minute${pluralMinutes}`
}
27 changes: 26 additions & 1 deletion api/oauth2.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"use strict";
const ejs = require('ejs');
const banlist = require("../misc/banlist.json");
const bannedUsers = banlist.banned_users;

const settings = require("../settings.json");

Expand Down Expand Up @@ -118,7 +121,29 @@ module.exports.load = async function (app, db) {
if (settings.whitelist.status) {
if (!settings.whitelist.users.includes(userinfo.id)) return res.send('Service is under maintenance.')
}

const bannedUser1 = banlist.banned_users.find(user => user.email === userinfo.email);
const isBanned = bannedUsers.some(user => user.email === userinfo.email && new Date(user.ban_until) > new Date());
if (isBanned) {
return ejs.renderFile(
`./themes/${newsettings.defaulttheme}/alerts/banned.ejs`,
{
ban_until: bannedUser1.ban_until,
userinfo: userinfo,
banlist: bannedUsers,
settings: newsettings,
db
},
null,
(err, str) => {
if (err) {
console.error(err);
res.status(500).send('Internal Server Error');
return;
}
res.status(200).send(str);
}
);
}
let guildsjson = await fetch(
'https://discord.com/api/users/@me/guilds',
{
Expand Down
8 changes: 1 addition & 7 deletions api/power.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ module.exports.load = async function (app, db) {
});

if (!response.ok) {
console.error(`Failed to start server. Status: ${response.status}`);
return res.json({ "success": false, "message": "Failed to start server" });
}

return res.json({ "success": true, "message": "Operation success!" });
} catch (error) {
console.error("Error during server start request:", error);
return res.json({ "success": false, "message": "Internal server error" });
}
});
Expand Down Expand Up @@ -68,13 +66,11 @@ module.exports.load = async function (app, db) {
});

if (!response.ok) {
console.error(`Failed to restart server. Status: ${response.status}`);
return res.json({ "success": false, "message": "Failed to start server" });
}

return res.json({ "success": true, "message": "Operation success!" });
} catch (error) {
console.error("Error during server restart request:", error);
return res.json({ "success": false, "message": "Internal server error" });
}
});
Expand Down Expand Up @@ -108,14 +104,12 @@ module.exports.load = async function (app, db) {
});

if (!response.ok) {
console.error(`Failed to start server. Status: ${response.status}`);
return res.json({ "success": false, "message": "Failed to start server" });
}

console.log("Server stopped successfully");

return res.json({ "success": true, "message": "Operation success!" });
} catch (error) {
console.error("Error during server start request:", error);
return res.json({ "success": false, "message": "Internal server error" });
}
});
Expand Down
7 changes: 5 additions & 2 deletions api/servers.js
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,10 @@ module.exports.load = async function (app, db) {
let newsettings = JSON.parse(fs.readFileSync("./settings.json").toString());
if (newsettings.api.client.allow.server.delete == true) {
if (req.session.pterodactyl.relationships.servers.data.filter(server => server.attributes.id == req.query.id).length == 0) return res.send("Could not find server with that ID.");

const server = req.session.pterodactyl.relationships.servers.data.find(server => server.attributes.id == req.query.id);
if (server.attributes.suspended) {
return res.send("You have tried to delete a suspended server on the panel, which is not possible. This is due to the prevention of users trying to abuse suspended servers. Contact support if you think this is an error.");
}
let deletionresults = await fetch(
settings.pterodactyl.domain + "/api/application/servers/" + req.query.id,
{
Expand Down Expand Up @@ -383,4 +386,4 @@ module.exports.load = async function (app, db) {
const createdServer = await db.get(`createdserver-${req.session.userinfo.id}`)
return res.json({ created: createdServer ?? false, cost: settings.renewals.cost })
})
};
};
Binary file removed assets/img/login_page.png
Binary file not shown.
2 changes: 1 addition & 1 deletion assets/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ html {
*/

body {
overflow: hidden;

/* Hide scrollbars */
margin: 0;
/* 1 */
Expand Down
39 changes: 0 additions & 39 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,41 +101,6 @@ const ejs = require("ejs");
const session = require("express-session");
const indexjs = require("./index.js");

//Load plugins

const path = require('path');

const pluginsFolderPath = './plugins'; // Change this to your actual plugins folder path

function loadPlugins() {
// Check if the plugins folder exists
if (fs.existsSync(pluginsFolderPath)) {
// Read the contents of the plugins folder
const files = fs.readdirSync(pluginsFolderPath);

// Check if the folder is not empty
if (files.length > 0) {
console.log('Loading plugins...');
// Iterate through each file in the folder
files.forEach((file) => {
// Load the plugin (you can customize this part based on your needs)
const pluginPath = path.join(pluginsFolderPath, file);
const plugin = require(pluginPath);
// Do something with the loaded plugin
console.log(`Loaded plugin: ${file}`);
});
} else {
console.log('No plugins found in the folder. Skipping.');
}
} else {
console.log('Plugins folder does not exist. Skipping.');
}
}

// Call the function to load plugins
loadPlugins();



// Load the website.

Expand Down Expand Up @@ -193,10 +158,6 @@ app.use(function(req, res, next) {
});






// Load the API files.

let apifiles = fs.readdirSync('./api').filter(file => file.endsWith('.js'));
Expand Down
13 changes: 13 additions & 0 deletions misc/banlist.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"banned_users": [
{
"email": "[email protected]",
"ban_until": "2024-06-01T00:00:00Z"
},
{
"email": "[email protected]",
"ban_until": "2025-01-15T00:00:00Z"
}
]
}

2 changes: 2 additions & 0 deletions misc/getAllServers.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Credits to Heliactyl as this helps Lapsus to check renewal status on all servers

const fetch = require('node-fetch')
const settings = require('../settings.json')

Expand Down
Loading

0 comments on commit ef1a427

Please sign in to comment.