├── .env ├── README.md ├── app.json ├── index.js ├── package.json └── routes ├── api.js └── discord.js /.env: -------------------------------------------------------------------------------- 1 | #Discord 2 | BOT_TOKEN= 3 | PREFIX=! 4 | GUILD_ID= 5 | ROLE_ID= 6 | 7 | #DB 8 | DB_USERNAME= 9 | DB_PASSWORD= 10 | HOST= 11 | DB_PORT= 12 | DB_NAME= 13 | 14 | #API 15 | API_BASE=http://127.0.0.1:5000 16 | API_KEY=api-key-here 17 | 18 | NODE_TLS_REJECT_UNAUTHORIZED=0 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # open-source-auth 2 | 3 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 4 | 5 | 6 | * Add all db information to Config Vars on heroku app: 7 | 8 | ``` 9 | DB_USERNAME= 10 | DB_PASSWORD= 11 | HOST= 12 | DB_PORT= 13 | DB_NAME= 14 | NODE_TLS_REJECT_UNAUTHORIZED=0 15 | ``` 16 | 17 | * Add all discord information to Config Vars on heroku app: 18 | 19 | ``` 20 | BOT_TOKEN= 21 | PREFIX=! 22 | GUILD_ID= 23 | ROLE_ID= 24 | ``` 25 | 26 | * Add all API information to Config Vars on heroku app: 27 | 28 | ``` 29 | API_BASE=http://127.0.0.1:5000 (api base is just the base url of your site, make sure there is no / on the end) 30 | API_KEY=api-key-here 31 | ``` 32 | 33 | 34 | ## API 35 | 36 | ### Binds a user 37 | ```javascript 38 | var options = { 39 | url: `${process.env.API_BASE}/api/bind/user`, 40 | method: "POST", 41 | body: { 42 | key: key, 43 | userID: userID, 44 | }, 45 | json: true, 46 | headers: { 47 | apiKey: process.env.API_KEY, 48 | }, 49 | }; 50 | ``` 51 | 52 | ### Unbinds a user 53 | ```javascript 54 | var options = { 55 | url: `${process.env.API_BASE}/api/unbind/user`, 56 | method: "POST", 57 | body: { 58 | key: key, 59 | userID: userID, 60 | }, 61 | json: true, 62 | headers: { 63 | apiKey: process.env.API_KEY, 64 | }, 65 | }; 66 | ``` 67 | 68 | ### Resets a users machine 69 | ```javascript 70 | var options = { 71 | url: `${process.env.API_BASE}/api/reset/machine`, 72 | method: "POST", 73 | body: { 74 | key: key, 75 | }, 76 | json: true, 77 | headers: { 78 | apiKey: process.env.API_KEY, 79 | }, 80 | }; 81 | ``` 82 | 83 | ### Sets a users machine 84 | ```javascript 85 | var options = { 86 | url: `${process.env.API_BASE}/api/set/machine`, 87 | method: "POST", 88 | body: { 89 | key: key, 90 | machine: machine 91 | }, 92 | json: true, 93 | headers: { 94 | apiKey: process.env.API_KEY, 95 | }, 96 | }; 97 | ``` 98 | 99 | ### Returns all info on a specific user (by user id) 100 | ```javascript 101 | var options = { 102 | url: `${process.env.API_BASE}/api/key`, 103 | method: "POST", 104 | body: { 105 | userID: userID, 106 | }, 107 | json: true, 108 | headers: { 109 | apiKey: process.env.API_KEY, 110 | }, 111 | }; 112 | ``` 113 | 114 | ### Returns all info on a specific user (by key) 115 | ```javascript 116 | var options = { 117 | url: `${process.env.API_BASE}/api/key`, 118 | method: "POST", 119 | body: { 120 | key: key 121 | }, 122 | json: true, 123 | headers: { 124 | apiKey: process.env.API_KEY, 125 | }, 126 | }; 127 | ``` 128 | 129 | 130 | ### Inserts a key into the database 131 | ```javascript 132 | var options = { 133 | url: `${process.env.API_BASE}/api/insert/key`, 134 | method: "POST", 135 | body: { 136 | type: type, 137 | }, 138 | json: true, 139 | headers: { 140 | apiKey: process.env.API_KEY, 141 | }, 142 | }; 143 | ``` 144 | 145 | ### Lists all users in the database 146 | ```javascript 147 | var options = { 148 | url: `${process.env.API_BASE}/api/list/users`, 149 | method: "GET", 150 | json: true, 151 | headers: { 152 | apiKey: process.env.API_KEY, 153 | }, 154 | }; 155 | ``` 156 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CharlieAIO Auth", 3 | "description": "Basic Auth app", 4 | "repository": "https://github.com/CharlieAIO/open-source-auth", 5 | "keywords": ["node", "express", "discord"] 6 | } 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const dotenv = require('dotenv'); 3 | dotenv.config() 4 | 5 | const api = require('./routes/api'); 6 | const discord =require('./routes/discord'); 7 | 8 | const app = express(); 9 | 10 | app.use(express.json()); 11 | 12 | app.use('/api', api) 13 | app.use('/',discord) 14 | 15 | app.listen(process.env.PORT || 5000, () => console.log(`Listening on port: ${process.env.port}`)) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-source-auth", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "author": "CharlieAIO#0001", 10 | "license": "ISC", 11 | "dependencies": { 12 | "discord.js": "^12.2.0", 13 | "dotenv": "^8.2.0", 14 | "express": "^4.17.1", 15 | "pg": "^8.3.0", 16 | "request": "^2.88.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /routes/api.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { Client } = require('pg'); 3 | 4 | const router = express.Router(); 5 | 6 | const db = new Client({ 7 | user: process.env.DB_USERNAME, 8 | password: process.env.DB_PASSWORD, 9 | database: process.env.DB_NAME, 10 | port: process.env.DB_PORT, 11 | host: process.env.HOST, 12 | ssl: true, 13 | }) 14 | 15 | function generate(length) { 16 | var result = ""; 17 | var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; 18 | var charactersLength = characters.length; 19 | for (var i = 0; i < length; i++) { 20 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 21 | } 22 | return result; 23 | } 24 | 25 | 26 | router.get('/', async (req, res) => { 27 | res.json({ 28 | version: '1.0.0' 29 | }) 30 | }) 31 | 32 | router.get('/create/key/table', async (req, res) => { 33 | if (req.get('apiKey') == process.env.API_KEY) { 34 | await db.connect() 35 | try { 36 | await db.query(`CREATE TABLE keys ("key" VARCHAR(255) NOT NULL, "type" VARCHAR(100) NOT NULL, "id" VARCHAR(100), "machineId" VARCHAR(255))`) 37 | await db.end() 38 | res.send('Table created').status(200) 39 | } catch(error) { 40 | await db.end() 41 | console.log(error) 42 | res.send('Failed to create table').status(400) 43 | } 44 | } else { 45 | res.sendStatus(403) 46 | } 47 | } 48 | ) 49 | 50 | router.post('/key', async (req, res) => { 51 | if (req.get('apiKey') == process.env.API_KEY) { 52 | await db.connect() 53 | try { 54 | if (req.body.key) { 55 | let results = await db.query(`select * from keys where key = '${req.body.key}'`); 56 | await db.end() 57 | res.json(results.rows[0]).status(200) 58 | } 59 | if (req.body.userID) { 60 | let results = await db.query(`select * from keys where id = '${req.body.userID}'`); 61 | await db.end() 62 | res.json(results.rows[0]).status(200) 63 | } 64 | } catch(error) { 65 | await db.end() 66 | console.log(error) 67 | res.json({ error }).status(400) 68 | } 69 | 70 | } else { 71 | res.sendStatus(403) 72 | } 73 | } 74 | ) 75 | 76 | 77 | 78 | router.get('/list/users', async (req, res) => { 79 | if (req.get('apiKey') == process.env.API_KEY) { 80 | await db.connect() 81 | try { 82 | let results = await db.query(`select * from keys`); 83 | await db.end() 84 | res.json(results.rows).status(200) 85 | } catch(error) { 86 | await db.end() 87 | console.log(error) 88 | res.json({ error }).status(400) 89 | } 90 | } else { 91 | res.sendStatus(401) 92 | } 93 | } 94 | ) 95 | 96 | 97 | router.post('/insert/key', async (req, res) => { 98 | if (req.get('apiKey') == process.env.API_KEY) { 99 | await db.connect() 100 | try{ 101 | var key = `${generate(4)}-${generate(4)}-${generate(4)}-${generate(4)}` 102 | // key : key type : discord id : machine id 103 | await db.query("insert into keys values ($1,$2,$3,$4)",[key,req.body.type,null,null]) 104 | await db.end(); 105 | res.send({key:key,type:req.body.type,status:'added'}).status(200) 106 | } catch(error) { 107 | console.log(error) 108 | await db.end() 109 | res.json({ error }).status(400) 110 | } 111 | }else{ 112 | res.sendStatus(401) 113 | } 114 | } 115 | ) 116 | 117 | router.post('/reset/machine', async (req, res) => { 118 | if (req.get('apiKey') == process.env.API_KEY) { 119 | await db.connect() 120 | try { 121 | let results = await db.query(`select * from keys where key = '${req.body.key}'`); 122 | if (results.rows.length == 0) { 123 | await db.end() 124 | return res.sendStatus(404) 125 | } 126 | await db.query(`update keys set "machineId"=null where key='${req.body.key}'`); 127 | await db.end() 128 | res.sendStatus(200) 129 | } catch(error) { 130 | console.log(error) 131 | await db.end() 132 | res.json({ error }).status(400) 133 | } 134 | 135 | }else{ 136 | res.sendStatus(401) 137 | } 138 | } 139 | ) 140 | 141 | router.post('/set/machine', async (req, res) => { 142 | if (req.get('apiKey') == process.env.API_KEY){ 143 | await db.connect() 144 | try { 145 | await db.query(`update keys set "machineId"='${req.body.machine}' where key='${req.body.key}'`); 146 | await db.end() 147 | res.sendStatus(200).end() 148 | } catch(error) { 149 | await db.end() 150 | console.log(error) 151 | res.json({ error }).status(400) 152 | } 153 | } else { 154 | res.sendStatus(401) 155 | } 156 | } 157 | ) 158 | 159 | 160 | router.post('/bind/user', async (req, res) => { 161 | if (req.get('apiKey') == process.env.API_KEY) { 162 | await db.connect() 163 | try { 164 | let results = await db.query(`select * from keys where key = '${req.body.key}'`); 165 | if (results.rows.length == 0) { 166 | await db.end() 167 | res.sendStatus(400) 168 | } 169 | if (results.rows[0].id == null) { 170 | await db.query(`update keys set "id"='${req.body.userID}' where key='${req.body.key}'`); 171 | await db.end() 172 | res.sendStatus(200) 173 | } else { 174 | await db.end() 175 | res.json({ error:"user already bound" }).status(400) 176 | } 177 | } catch(error) { 178 | await db.end() 179 | console.log(error) 180 | res.json({ error }).status(400) 181 | } 182 | 183 | } else { 184 | res.sendStatus(401) 185 | } 186 | } 187 | ) 188 | 189 | router.post('/unbind/user', async (req, res) => { 190 | if (req.get('apiKey') == process.env.API_KEY) { 191 | await db.connect() 192 | try { 193 | let results = await db.query(`select * from keys where key = '${req.body.key}'`); 194 | if(results.rows.length == 0){ 195 | await db.end() 196 | res.sendStatus(404).end() 197 | } 198 | await db.query(`update keys set "id"=null where key='${req.body.key}'`); 199 | await db.end() 200 | res.sendStatus(200).end() 201 | } catch(error) { 202 | await db.end() 203 | console.log(error) 204 | res.json({ error }).status(400) 205 | } 206 | 207 | } else { 208 | res.sendStatus(401) 209 | } 210 | } 211 | ) 212 | 213 | module.exports = router -------------------------------------------------------------------------------- /routes/discord.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const { Client, MessageEmbed } = require("discord.js"); 4 | var request = require("request"); 5 | 6 | const client = new Client(); 7 | 8 | client.on("ready", () => { 9 | console.log(`Logged in as ${client.user.tag}!`); 10 | }); 11 | 12 | client.on("message", (message ) => { 13 | if(message.content.startsWith(process.env.PREFIX)){ 14 | 15 | const args = message.content.slice(process.env.PREFIX.length).trim().split(/ +/); 16 | const command = args.shift().toLowerCase(); 17 | 18 | if(command == "help"){ 19 | const embed = new MessageEmbed() 20 | .setTitle('CharlieAIO Auth') 21 | .setColor(0x4bd670) 22 | .setDescription(`${message.author}'s Key`) 23 | .addFields( 24 | { name: '!bind ', value: 'Use this command to bind your key', inline:false }, 25 | { name: '!unbind ', value: 'Use this command to unbind your key', inline:false }, 26 | { name: '!reset ', value: 'Use this command to reset your key', inline:false }, 27 | { name: '!key', value: 'Use this command to view your key and other info', inline:false }, 28 | ) 29 | const user = client.users.cache.get(message.author.id); 30 | user.send(embed); 31 | 32 | } 33 | if(command == "bind"){ 34 | var key = args[0] 35 | 36 | var options = { 37 | url: `${process.env.API_BASE}/api/bind/user`, 38 | method: "POST", 39 | body: { 40 | key: key, 41 | userID: message.author.id, 42 | }, 43 | json: true, 44 | headers: { 45 | apiKey: process.env.API_KEY, 46 | }, 47 | }; 48 | request(options, function(error, response, body){ 49 | if(response.statusCode == 200){ 50 | const guild = client.guilds.cache.get(process.env.GUILD_ID); 51 | let guildMember = guild.member(message.author.id); 52 | guildMember.roles 53 | .add(process.env.ROLE_ID) 54 | .catch(console.error); 55 | 56 | const embed = new MessageEmbed() 57 | .setTitle('CharlieAIO Auth') 58 | .setColor(0x4bd670) 59 | .setDescription(`Successfully bound!`); 60 | const user = client.users.cache.get(message.author.id); 61 | user.send(embed); 62 | }else{ 63 | const embed = new MessageEmbed() 64 | .setTitle('CharlieAIO Auth') 65 | .setColor(0x4bd670) 66 | .setDescription(`Failed to bind`); 67 | const user = client.users.cache.get(message.author.id); 68 | user.send(embed) 69 | } 70 | 71 | }) 72 | 73 | 74 | } 75 | 76 | if(command == "unbind"){ 77 | var key = args[0] 78 | 79 | var options = { 80 | url: `${process.env.API_BASE}/api/unbind/user`, 81 | method: "POST", 82 | body: { 83 | key: key, 84 | userID: message.author.id, 85 | }, 86 | json: true, 87 | headers: { 88 | apiKey: process.env.API_KEY, 89 | }, 90 | }; 91 | request(options, function(error, response, body){ 92 | if(response.statusCode == 200){ 93 | const guild = client.guilds.cache.get(process.env.GUILD_ID); 94 | let guildMember = guild.member(message.author.id); 95 | guildMember.roles 96 | .remove(process.env.ROLE_ID) 97 | .catch(console.error); 98 | 99 | const embed = new MessageEmbed() 100 | .setTitle('CharlieAIO Auth') 101 | .setColor(0x4bd670) 102 | .setDescription(`Successfully unbound!`); 103 | const user = client.users.cache.get(message.author.id); 104 | user.send(embed); 105 | }else{ 106 | const embed = new MessageEmbed() 107 | .setTitle('CharlieAIO Auth') 108 | .setColor(0x4bd670) 109 | .setDescription(`Failed to unbind`); 110 | const user = client.users.cache.get(message.author.id); 111 | user.send(embed) 112 | } 113 | 114 | }) 115 | 116 | 117 | } 118 | 119 | if(command == "reset"){ 120 | var key = args[0] 121 | 122 | var options = { 123 | url: `${process.env.API_BASE}/api/reset/machine`, 124 | method: "POST", 125 | body: { 126 | key: key, 127 | }, 128 | json: true, 129 | headers: { 130 | apiKey: process.env.API_KEY, 131 | }, 132 | }; 133 | request(options, function(error, response, body){ 134 | if(response.statusCode == 200){ 135 | const embed = new MessageEmbed() 136 | .setTitle('CharlieAIO Auth') 137 | .setColor(0x4bd670) 138 | .setDescription(`Successfully reset!`); 139 | const user = client.users.cache.get(message.author.id); 140 | user.send(embed); 141 | }else{ 142 | const embed = new MessageEmbed() 143 | .setTitle('CharlieAIO Auth') 144 | .setColor(0x4bd670) 145 | .setDescription(`Failed to reset`); 146 | const user = client.users.cache.get(message.author.id); 147 | user.send(embed) 148 | } 149 | 150 | }) 151 | 152 | 153 | } 154 | 155 | if(command == "key"){ 156 | var key = args[0] 157 | 158 | var options = { 159 | url: `${process.env.API_BASE}/api/key`, 160 | method: "POST", 161 | body: { 162 | userID: message.author.id, 163 | }, 164 | json: true, 165 | headers: { 166 | apiKey: process.env.API_KEY, 167 | }, 168 | }; 169 | request(options, function(error, response, body){ 170 | if(response.statusCode == 200){ 171 | if(body == undefined){ 172 | const embed = new MessageEmbed() 173 | .setTitle('CharlieAIO Auth') 174 | .setColor(0x4bd670) 175 | .setDescription(`${message.author} has no key bound.`) 176 | const user = client.users.cache.get(message.author.id); 177 | user.send(embed); 178 | 179 | }else{ 180 | const embed = new MessageEmbed() 181 | .setTitle('CharlieAIO Auth') 182 | .setColor(0x4bd670) 183 | .setDescription(`${message.author}'s Key`) 184 | .addFields( 185 | { name: 'License Key', value: body.key, inline:false }, 186 | { name: 'License Type', value: body.type, inline: false }, 187 | { name: 'Machine', value: body.machineId , inline: false }, 188 | ) 189 | const user = client.users.cache.get(message.author.id); 190 | user.send(embed); 191 | } 192 | } 193 | 194 | }) 195 | 196 | 197 | } 198 | if(command == "gen"){ 199 | var type = args[0] 200 | 201 | var options = { 202 | url: `${process.env.API_BASE}/api/insert/key`, 203 | method: "POST", 204 | body: { 205 | type: type, 206 | }, 207 | json: true, 208 | headers: { 209 | apiKey: process.env.API_KEY, 210 | }, 211 | }; 212 | request(options, function(error, response, body){ 213 | if(response.statusCode == 200){ 214 | const embed = new MessageEmbed() 215 | .setTitle('CharlieAIO Auth') 216 | .setColor(0x4bd670) 217 | .addFields( 218 | { name: 'License Key', value: body.key, inline:false }, 219 | { name: 'License Type', value: body.type, inline:false }, 220 | ) 221 | .setDescription('Key Generated') 222 | const user = client.users.cache.get(message.author.id); 223 | user.send(embed); 224 | 225 | 226 | } 227 | else{ 228 | const embed = new MessageEmbed() 229 | .setTitle('CharlieAIO Auth') 230 | .setColor(0x4bd670) 231 | .setDescription('Failed to generate key') 232 | const user = client.users.cache.get(message.author.id); 233 | user.send(embed); 234 | } 235 | 236 | }) 237 | 238 | 239 | } 240 | if(!(['help','reset','bind','unbind','key','gen'].includes(command))){ 241 | const embed = new MessageEmbed() 242 | .setTitle('CharlieAIO Auth') 243 | .setColor(0x4bd670) 244 | .setDescription(`That command wasnt found, use !help`) 245 | 246 | const user = client.users.cache.get(message.author.id); 247 | user.send(embed); 248 | } 249 | 250 | 251 | } 252 | }); 253 | 254 | 255 | client.login(process.env.BOT_TOKEN); 256 | module.exports = router --------------------------------------------------------------------------------