Fix up some bugs with backend discord+google integration

master
sigonasr2 3 years ago
parent 5c93676b32
commit ad957f15be
  1. 1
      node_modules/discord-oauth2/.eslintignore
  2. 35
      node_modules/discord-oauth2/.eslintrc.json
  3. 21
      node_modules/discord-oauth2/.github/ISSUE_TEMPLATE/can-t-get-it-to-work.md
  4. 18
      node_modules/discord-oauth2/.github/workflows/ci.yml
  5. 21
      node_modules/discord-oauth2/LICENSE
  6. 358
      node_modules/discord-oauth2/README.md
  7. 136
      node_modules/discord-oauth2/index.d.ts
  8. 3
      node_modules/discord-oauth2/index.js
  9. 91
      node_modules/discord-oauth2/lib/eris/errors/DiscordHTTPError.js
  10. 103
      node_modules/discord-oauth2/lib/eris/errors/DiscordRESTError.js
  11. 305
      node_modules/discord-oauth2/lib/eris/rest/RequestHandler.js
  12. 105
      node_modules/discord-oauth2/lib/eris/util/SequentialBucket.js
  13. 218
      node_modules/discord-oauth2/lib/oauth.js
  14. 56
      node_modules/discord-oauth2/package.json
  15. 11
      node_modules/secrethash/package.json
  16. 5
      package-lock.json
  17. 1
      package.json
  18. 66
      server.js

@ -0,0 +1 @@
node_modules

@ -0,0 +1,35 @@
{
"env": {
"es6": true,
"node": true
},
"parserOptions": {
"ecmaVersion": 2020
},
"extends": "eslint:recommended",
"rules": {
"semi": "error",
"no-var": "error",
"prefer-const": "error",
"keyword-spacing": "error",
"eqeqeq": "error",
"eol-last": "error",
"brace-style": ["error", "stroustrup"],
"comma-dangle": ["error", "always-multiline"],
"object-curly-spacing": ["error", "always"],
"quotes": ["error", "double", {
"allowTemplateLiterals": true
}],
"indent": ["error", "tab", {
"SwitchCase": 1,
"flatTernaryExpressions": true
}],
"object-curly-newline": ["error", {
"ExportDeclaration": "never",
"ImportDeclaration": "always"
}]
}
}

@ -0,0 +1,21 @@
---
name: Can't get it to work
about: Use this template if you are having issues with the library (all issues opened
for issues with the library that don't follow this template will be ignored and
closed).
title: ''
labels: ''
assignees: reboxer
---
**Describe the error**
A clear and concise description of what the error is.
**NodeJS version**
*Your NodeJS version*
**Relevant code**
```js
// Put here the code you are using that is not working
```

@ -0,0 +1,18 @@
name: Run ESLint
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
lint:
name: Run ESlint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: yarn run lint

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 reboxer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,358 @@
# discord-oauth2 [![NPM version](https://img.shields.io/npm/v/discord-oauth2.svg?style=flat-square)](https://www.npmjs.com/package/discord-oauth2)
A really simple to use module to use discord's OAuth2 API.
Please check out discord's OAuth2 documentation: https://discord.com/developers/docs/topics/oauth2
### Installing
```bash
npm install discord-oauth2
```
# Class constructor
One parameter is passed to the class constructor:
### `Options`
Since the module uses a modified version of [Eris](https://github.com/abalabahaha/eris) request handler, it takes the same options, all of them default to the default Eris Client options if no options are passed.
Request handler options:
```
requestTimeout: A number of milliseconds before requests are considered timed out.
latencyThreshold: The average request latency at which the RequestHandler will start emitting latency errors.
ratelimiterOffset: A number of milliseconds to offset the ratelimit timing calculations by.
```
Others, you can pass these options to the class constructor so you don't have to pass them each time you call a function:
```
version: The Discord API version to use. Defaults to "v7".
clientId: Your application's client id.
clientSecret: Your application's client secret.
redirectUri: Your URL redirect uri.
credentials: Base64 encoding of the UTF-8 encoded credentials string of your application, you can pass this in the constructor to not pass it every time you want to use the revokeToken() method.
```
# Events
In the Eris Library, client extends the `events` modules and the client is passed to the RequestHandler so it's able to emit events, this modified RequestHandler extends `events` so it can emit the same events.
There are only two events, `debug` and `warn`.
# Methods
### `tokenRequest()`
Only takes an object with the following properties:
`clientId`: Your application's client id. Can be omitted if provided on the client constructor.
`clientSecret`: Your application's client secret. Can be omitted if provided on the client constructor.
`scope`: The scopes requested in your authorization url, can be either a space-delimited string of scopes, or an array of strings containing scopes.
`redirectUri`: Your URL redirect uri. Can be omitted if provided on the client constructor.
`grantType`: The grant type to set for the request, either authorization_code or refresh_token.
`code`: The code from the querystring (grantType `authorization_code` only).
`refreshToken`: The user's refresh token (grantType `refresh_token` only).
Returns a promise which resolves in an object with the access token.
Please refer to discord's OAuth2 [documentation](https://discord.com/developers/docs/topics/oauth2#authorization-code-grant-access-token-exchange-example) for the parameters needed.
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2();
oauth.tokenRequest({
clientId: "332269999912132097",
clientSecret: "937it3ow87i4ery69876wqire",
code: "query code",
scope: "identify guilds",
grantType: "authorization_code",
redirectUri: "http://localhost/callback",
}).then(console.log)
```
Using class constructor options, array of scopes and grantType refresh_token:
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2({
clientId: "332269999912132097",
clientSecret: "937it3ow87i4ery69876wqire",
redirectUri: "http://localhost/callback",
});
oauth.tokenRequest({
// clientId, clientSecret and redirectUri are omitted, as they were already set on the class constructor
refreshToken: "D43f5y0ahjqew82jZ4NViEr2YafMKhue",
grantType: "refresh_token",
scope: ["identify", "guilds"],
});
// On successful request both requesting and refreshing an access token return the same object
/*
{
"access_token": "6qrZcUqja7812RVdnEKjpzOL4CvHBFG",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "D43f5y0ahjqew82jZ4NViEr2YafMKhue",
"scope": "identify guilds"
}
*/
```
### `revokeToken()`
Takes two parameters, the first one is the access_token from the user, the second is a Base64 encoding of the UTF-8 encoded credentials string of your application.
Returns a promise which resolves in an empty object if successful.
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2();
const clientID = "332269999912132097";
const client_secret = "937it3ow87i4ery69876wqire";
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
// You must encode your client ID along with your client secret including the colon in between
const credentials = Buffer.from(`${clientID}:${client_secret}`).toString("base64"); // MzMyMjY5OTk5OTEyMTMyMDk3OjkzN2l0M293ODdpNGVyeTY5ODc2d3FpcmU=
oauth.revokeToken(access_token, credentials).then(console.log); // {}
```
### `getUser()`
Only takes one parameter which is the user's access token.
Returns the [user](https://discord.com/developers/docs/resources/user#user-object) object of the requester's account, this requires the `identify` scope, which will return the object without an email, and optionally the `email` scope, which returns the object with an email.
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2();
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
oauth.getUser(access_token).then(console.log);
/*
{
username: '1337 Krew',
locale: 'en-US',
mfa_enabled: true,
flags: 128,
avatar: '8342729096ea3675442027381ff50dfe',
discriminator: '4421',
id: '80351110224678912'
}
*/
```
### `getUserGuilds()`
Only takes one parameter which is the user's access token.
Returns a list of partial [guild](https://discord.com/developers/docs/resources/guild#guild-object) objects the current user is a member of. Requires the `guilds` scope.
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2();
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
oauth.getUserGuilds(access_token).then(console.log);
/*
{
"id": "80351110224678912",
"name": "1337 Krew",
"icon": "8342729096ea3675442027381ff50dfe",
"owner": true,
"permissions": 36953089,
"permissions_new": "36953089"
}
*/
```
### `getUserConnections()`
Only takes one parameter which is the user's access token.
Returns a list of [connection](https://discord.com/developers/docs/resources/user#connection-object) objects. Requires the `connections` OAuth2 scope.
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2();
const access_token = "6qrZcUqja7812RVdnEKjpzOL4CvHBFG";
oauth.getUserConnections(access_token).then(console.log);
/*
[ { verified: true,
name: 'epicusername',
show_activity: true,
friend_sync: false,
type: 'twitch',
id: '31244565',
visibility: 1 } ]
*/
```
### `addMember()`
Force join a user to a guild (server).
Takes an object with the following properties:
`accessToken`: The user access token.
`botToken`: The token of the bot used to authenticate.
`guildId`: The ID of the guild to join.
`userId`: The ID of the user to be added to the guild.
Optional properties (the above ones are required):
`nickname`: Value to set users nickname to.
`roles`: Array of role ids the member is assigned.
`mute`: Whether the user is muted in voice channels.
`deaf`: Whether the user is deafened in voice channels.
Returns a member object if the user wasn't part of the guild, else, returns an empty string (length 0).
```js
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2();
oauth.addMember({
accessToken: "2qRZcUqUa9816RVnnEKRpzOL2CvHBgF",
botToken: "NDgyMjM4ODQzNDI1MjU5NTIz.XK93JQ.bnLsc71_DGum-Qnymb4T5F6kGY8",
guildId: "216488324594438692",
userId: "80351110224678912",
nickname: "george michael",
roles: ["624615851966070786"],
mute: true,
deaf: true,
}).then(console.log); // Member object or empty string
/*
{
nick: 'george michael',
user: {
username: 'some username',
discriminator: '0001',
id: '421610529323943943',
avatar: null
},
roles: [ '324615841966570766' ],
premium_since: null,
deaf: true,
mute: true,
joined_at: '2019-09-20T14:44:12.603123+00:00'
}
*/
```
### `generateAuthUrl`
Dynamically generate an OAuth2 URL.
Takes an object with the following properties:
`clientId`: Your application's client id. Can be omitted if provided on the client constructor.
`prompt`: Controls how existing authorizations are handled, either consent or none (for passthrough scopes authorization is always required).
`scope`: The scopes requested in your authorization url, can be either a space-delimited string of scopes, or an array of strings containing scopes.
`redirectUri`: Your URL redirect uri. Can be omitted if provided on the client constructor.
`responseType`: The response type, either code or token (token is for client-side web applications only). Defaults to code.
`state`: A unique cryptographically secure string (https://discord.com/developers/docs/topics/oauth2#state-and-security).
`permissions`: The permissions number for the bot invite (only with bot scope) (https://discord.com/developers/docs/topics/permissions).
`guildId`: The guild id to pre-fill the bot invite (only with bot scope).
`disableGuildSelect`: Disallows the user from changing the guild for the bot invite, either true or false (only with bot scope).
```js
const crypto = require('crypto')
const DiscordOauth2 = require("discord-oauth2");
const oauth = new DiscordOauth2({
clientId: "332269999912132097",
clientSecret: "937it3ow87i4ery69876wqire",
redirectUri: "http://localhost/callback",
});
const url = oauth.generateAuthUrl({
scope: ["identify", "guilds"],
state: crypto.randomBytes(16).toString("hex"), // Be aware that randomBytes is sync if no callback is provided
});
console.log(url);
// https://discord.com/api/oauth2/authorize?client_id=332269999912132097&redirect_uri=http%3A%2F%2Flocalhost%2Fcallback&response_type=code&scope=identify%20guilds&state=132054f372bfca771de3dfe54aaacece
```
# Debugging
By default when you log an error to the console, it will look something like this `DiscordHTTPError: 400 Bad Request on POST /api/v7/oauth2/token` followed by a very long stack trace what most of the times won't be useful (if you already know where the function is called).
To easily debug any issues you are having, you can access the following properties of the error object thrown:
`req`: The HTTP request sent to discord.
`res`: The HTTP response sent from discord to our request.
`code`: If the error is a `DiscordHTTPError`, it will be the HTTP status code of the response (same as `res.statusCode`).<br />
If the error is a `DiscordRESTError`, it will be a [Discord API JSON error code](https://discord.com/developers/docs/topics/opcodes-and-status-codes#json-json-error-codes).
`response`: An object containing properties that describe the error.<br />
If the error is a `DiscordHTTPError`, the object will have the `error` and `error_description` properties.<br />
If the error is a `DiscordRESTError`, the object will have the `message` and `code` (JSON error code. See `code`.) properties.
`message`: If the error is a `DiscordHTTPError`, it will be a string including the status of the HTTP request and the endpoint used.<br />
If the error is a `DiscordRESTError`, it will be a string including the error code and it's meaning.
`stack`: The error stack trace.
```js
// error.response for DiscordRESTError
{
message: 'Missing Permissions',
code: 50013
}
```
```js
// error.response for DiscordHTTPError
{
error: 'invalid_request',
error_description: 'Invalid "code" in request.'
}
```
# Contributing
All contributions are welcome.

@ -0,0 +1,136 @@
import { EventEmitter } from "events";
interface User {
id: string;
username: string;
discriminator: string;
avatar: string | null | undefined;
mfa_enabled?: true;
locale?: string;
verified?: boolean;
email?: string | null | undefined;
flags?: number;
premium_type?: number;
public_flags?: number;
}
interface Member {
user?: User;
nick: string | null | undefined;
roles: string[];
joined_at: number;
premium_since?: number | null | undefined;
deaf: boolean;
mute: boolean;
}
// This is not accurate as discord sends a partial object
interface Integration {
id: string;
name: string;
type: string;
enabled: boolean;
syncing: boolean;
role_id: string;
enable_emoticons?: boolean;
expire_behavior: 0 | 1;
expire_grace_period: number;
user?: User;
account: {
id: string;
name: string;
};
synced_at: number;
subscriber_count: number;
revoked: boolean;
application?: Application;
}
interface Connection {
id: string;
name: string;
type: string;
revoked?: string;
integrations?: Integration[];
verified: boolean;
friend_sync: boolean;
show_activity: boolean;
visibility: 0 | 1;
}
interface Application {
id: string;
name: string;
icon: string | null | undefined;
description: string;
summary: string;
bot?: User;
}
interface TokenRequestResult {
access_token: string;
token_type: string;
expires_in: number;
refresh_token: string;
scope: string;
}
interface PartialGuild {
id: string;
name: string;
icon: string | null | undefined;
owner?: boolean;
permissions?: number;
features: string[];
permissions_new?: string;
}
declare class OAuth extends EventEmitter {
constructor(opts?: {
version?: string,
clientId?: string,
redirectUri?: string,
credentials?: string,
clientSecret?: string,
requestTimeout?: number,
latencyThreshold?: number,
ratelimiterOffset?: number,
});
on(event: "debug" | "warn", listener: (message: string) => void): this;
tokenRequest(opts: {
code?: string,
scope: string[] | string,
clientId?: string,
grantType: "authorization_code" | "refresh_token",
redirectUri?: string,
refreshToken?: string,
clientSecret?: string,
}): Promise<TokenRequestResult>;
revokeToken(access_token: string, credentials?: string): Promise<string>;
getUser(access_token: string): Promise<User>;
getUserGuilds(access_token: string): Promise<PartialGuild[]>;
getUserConnections(access_token: string): Promise<Connection[]>;
addMember(opts: {
deaf?: boolean,
mute?: boolean,
roles?: string[],
nickname?: string,
userId: string,
guildId: string,
botToken: string,
accessToken: string,
}): Promise<Member>;
generateAuthUrl(opts: {
scope: string[] | string,
state?: string,
clientId?: string,
prompt?: "consent" | "none",
redirectUri?: string,
responseType?: "code" | "token",
permissions?: number,
guildId?: string,
disableGuildSelect?: boolean,
}): string;
}
export = OAuth;

@ -0,0 +1,3 @@
"use strict";
const OAuth = require("./lib/oauth");
module.exports = OAuth;

@ -0,0 +1,91 @@
/*
The MIT License (MIT)
Copyright (c) 2016-2020 abalabahaha
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* eslint-disable no-prototype-builtins */
"use strict";
class DiscordHTTPError extends Error {
constructor(req, res, response, stack) {
super();
Object.defineProperty(this, "req", {
enumerable: false,
value: req,
writable: false,
});
Object.defineProperty(this, "res", {
enumerable: false,
value: res,
writable: false,
});
Object.defineProperty(this, "response", {
enumerable: false,
value: response,
writable: false,
});
Object.defineProperty(this, "code", {
value: res.statusCode,
writable: false,
});
let message = `${this.name}: ${res.statusCode} ${res.statusMessage} on ${req.method} ${req.path}`;
const errors = this.flattenErrors(response);
if (errors.length > 0) {
message += "\n " + errors.join("\n ");
}
Object.defineProperty(this, "message", {
value: message,
writable: false,
});
if (stack) {
Object.defineProperty(this, "stack", {
value: this.message + "\n" + stack,
writable: false,
});
}
else {
Error.captureStackTrace(this, DiscordHTTPError);
}
}
get name() {
return this.constructor.name;
}
flattenErrors(errors, keyPrefix = "") {
let messages = [];
for (const fieldName in errors) {
if (!errors.hasOwnProperty(fieldName) || fieldName === "message" || fieldName === "code") {
continue;
}
if (Array.isArray(errors[fieldName])) {
messages = messages.concat(errors[fieldName].map((str) => `${keyPrefix + fieldName}: ${str}`));
}
}
return messages;
}
}
module.exports = DiscordHTTPError;

@ -0,0 +1,103 @@
/*
The MIT License (MIT)
Copyright (c) 2016-2020 abalabahaha
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* eslint-disable no-prototype-builtins */
"use strict";
class DiscordRESTError extends Error {
constructor(req, res, response, stack) {
super();
Object.defineProperty(this, "req", {
enumerable: false,
value: req,
writable: false,
});
Object.defineProperty(this, "res", {
enumerable: false,
value: res,
writable: false,
});
Object.defineProperty(this, "response", {
enumerable: false,
value: response,
writable: false,
});
Object.defineProperty(this, "code", {
value: +response.code || -1,
writable: false,
});
let message = this.name + ": " + (response.message || "Unknown error");
if (response.errors) {
message += "\n " + this.flattenErrors(response.errors).join("\n ");
}
else {
const errors = this.flattenErrors(response);
if (errors.length > 0) {
message += "\n " + errors.join("\n ");
}
}
Object.defineProperty(this, "message", {
value: message,
writable: false,
});
if (stack) {
Object.defineProperty(this, "stack", {
value: this.message + "\n" + stack,
writable: false,
});
}
else {
Error.captureStackTrace(this, DiscordRESTError);
}
}
get name() {
return `${this.constructor.name} [${this.code}]`;
}
flattenErrors(errors, keyPrefix = "") {
let messages = [];
for (const fieldName in errors) {
if (!errors.hasOwnProperty(fieldName) || fieldName === "message" || fieldName === "code") {
continue;
}
if (errors[fieldName]._errors) {
messages = messages.concat(errors[fieldName]._errors.map((obj) => `${keyPrefix + fieldName}: ${obj.message}`));
}
else if (Array.isArray(errors[fieldName])) {
messages = messages.concat(errors[fieldName].map((str) => `${keyPrefix + fieldName}: ${str}`));
}
else if (typeof errors[fieldName] === "object") {
messages = messages.concat(this.flattenErrors(errors[fieldName], keyPrefix + fieldName + "."));
}
}
return messages;
}
}
module.exports = DiscordRESTError;

@ -0,0 +1,305 @@
/*
The MIT License (MIT)
Copyright (c) 2016-2020 abalabahaha
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
"use strict";
const DiscordHTTPError = require("../errors/DiscordHTTPError");
const DiscordRESTError = require("../errors/DiscordRESTError");
const HTTPS = require("https");
const SequentialBucket = require("../util/SequentialBucket");
const EventEmitter = require("events");
/**
* Handles API requests
*/
class RequestHandler extends EventEmitter {
constructor(options) {
super();
this.version = options.version;
this.userAgent = `Discord-OAuth2 (https://github.com/reboxer/discord-oauth2, ${require("../../../package.json").version})`;
this.ratelimits = {};
this.requestTimeout = options.requestTimeout;
this.latencyThreshold = options.latencyThreshold;
this.latencyRef = {
latency: 500,
offset: options.ratelimiterOffset,
raw: new Array(10).fill(500),
timeOffset: 0,
timeOffsets: new Array(10).fill(0),
lastTimeOffsetCheck: 0,
};
this.globalBlock = false;
this.readyQueue = [];
}
globalUnblock() {
this.globalBlock = false;
while (this.readyQueue.length > 0) {
this.readyQueue.shift()();
}
}
// We need this for the Add Guild Member endpoint
routefy(url) {
return url.replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, function(match, p) {
return p === "guilds" ? match : `/${p}/:id`;
});
}
/**
* Make an API request
* @arg {String} method Uppercase HTTP method
* @arg {String} url URL of the endpoint
* @arg {Object} options
* @arg {Object} [options.auth]
* @arg {String} [options.auth.type] The type of Authorization to use in the header, wheather Basic, Bearer or Bot
* @arg {String} [options.auth.creds] The credentials used for the authentication (bot or user access token), if Basic, a base64 string with application's credentials must be passed
* @arg {String} options.contentType The content type to set in the headers of the request
* @arg {Object} [body] Request payload
* @returns {Promise<Object>} Resolves with the returned JSON data
*/
request(method, url, body, options, _route, short) {
const route = _route || this.routefy(url, method);
const _stackHolder = {}; // Preserve async stack
Error.captureStackTrace(_stackHolder);
return new Promise((resolve, reject) => {
let attempts = 0;
const actualCall = (cb) => {
const headers = {
"User-Agent": this.userAgent,
"Content-Type": options.contentType,
};
let data;
try {
if (options.auth) {
headers["Authorization"] = `${options.auth.type} ${options.auth.creds}`;
}
if (headers["Content-Type"] === "application/json") {
data = JSON.stringify(body);
}
else {
data = body;
}
}
catch (err) {
cb();
reject(err);
return;
}
const req = HTTPS.request({
method: method,
host: "discord.com",
path: `/api/${this.version}` + url,
headers: headers,
});
let reqError;
req.once("abort", () => {
cb();
reqError = reqError || new Error(`Request aborted by client on ${method} ${url}`);
reqError.req = req;
reject(reqError);
}).once("error", (err) => {
reqError = err;
req.abort();
});
let latency = Date.now();
req.once("response", (resp) => {
latency = Date.now() - latency;
this.latencyRef.raw.push(latency);
this.latencyRef.latency = this.latencyRef.latency - ~~(this.latencyRef.raw.shift() / 10) + ~~(latency / 10);
const headerNow = Date.parse(resp.headers["date"]);
if (this.latencyRef.lastTimeOffsetCheck < Date.now() - 5000) {
const timeOffset = ~~((this.latencyRef.lastTimeOffsetCheck = Date.now()) - headerNow);
if (this.latencyRef.timeOffset - this.latencyRef.latency >= this.latencyThreshold && timeOffset - this.latencyRef.latency >= this.latencyThreshold) {
this.emit("warn", new Error(`Your clock is ${this.latencyRef.timeOffset}ms behind Discord's server clock. Please check your connection and system time.`));
}
this.latencyRef.timeOffset = ~~(this.latencyRef.timeOffset - this.latencyRef.timeOffsets.shift() / 10 + timeOffset / 10);
this.latencyRef.timeOffsets.push(timeOffset);
}
resp.once("aborted", () => {
cb();
reqError = reqError || new Error(`Request aborted by server on ${method} ${url}`);
reqError.req = req;
reject(reqError);
});
let response = "";
const _respStream = resp;
_respStream.on("data", (str) => {
response += str;
}).on("error", (err) => {
reqError = err;
req.abort();
}).once("end", () => {
const now = Date.now();
if (resp.headers["x-ratelimit-limit"]) {
this.ratelimits[route].limit = +resp.headers["x-ratelimit-limit"];
}
if (method !== "GET" && (resp.headers["x-ratelimit-remaining"] === undefined || resp.headers["x-ratelimit-limit"] === undefined) && this.ratelimits[route].limit !== 1) {
this.emit("debug", `Missing ratelimit headers for SequentialBucket(${this.ratelimits[route].remaining}/${this.ratelimits[route].limit}) with non-default limit\n`
+ `${resp.statusCode} ${resp.headers["content-type"]}: ${method} ${route} | ${resp.headers["cf-ray"]}\n`
+ "content-type = " + "\n"
+ "x-ratelimit-remaining = " + resp.headers["x-ratelimit-remaining"] + "\n"
+ "x-ratelimit-limit = " + resp.headers["x-ratelimit-limit"] + "\n"
+ "x-ratelimit-reset = " + resp.headers["x-ratelimit-reset"] + "\n"
+ "x-ratelimit-global = " + resp.headers["x-ratelimit-global"]);
}
this.ratelimits[route].remaining = resp.headers["x-ratelimit-remaining"] === undefined ? 1 : +resp.headers["x-ratelimit-remaining"] || 0;
if (resp.headers["retry-after"]) {
if (resp.headers["x-ratelimit-global"]) {
this.globalBlock = true;
setTimeout(() => this.globalUnblock(), +resp.headers["retry-after"] || 1);
}
else {
this.ratelimits[route].reset = (+resp.headers["retry-after"] || 1) + now;
}
}
else if (resp.headers["x-ratelimit-reset"]) {
if ((~route.lastIndexOf("/reactions/:id")) && (+resp.headers["x-ratelimit-reset"] * 1000 - headerNow) === 1000) {
this.ratelimits[route].reset = Math.max(now + 250 - this.latencyRef.timeOffset, now);
}
else {
this.ratelimits[route].reset = Math.max(+resp.headers["x-ratelimit-reset"] * 1000 - this.latencyRef.timeOffset, now);
}
}
else {
this.ratelimits[route].reset = now;
}
if (resp.statusCode !== 429) {
this.emit("debug", `${body && body.content} ${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
}
if (resp.statusCode >= 300) {
if (resp.statusCode === 429) {
this.emit("debug", `${resp.headers["x-ratelimit-global"] ? "Global" : "Unexpected"} 429 (╯°□°)╯︵ ┻━┻: ${response}\n${body && body.content} ${now} ${route} ${resp.statusCode}: ${latency}ms (${this.latencyRef.latency}ms avg) | ${this.ratelimits[route].remaining}/${this.ratelimits[route].limit} left | Reset ${this.ratelimits[route].reset} (${this.ratelimits[route].reset - now}ms left)`);
if (resp.headers["retry-after"]) {
setTimeout(() => {
cb();
this.request(method, url, body, options, route, true).then(resolve).catch(reject);
}, +resp.headers["retry-after"]);
return;
}
else {
cb();
this.request(method, url, body, options, route, true).then(resolve).catch(reject);
return;
}
}
else if (resp.statusCode === 502 && ++attempts < 4) {
this.emit("debug", "A wild 502 appeared! Thanks CloudFlare!");
setTimeout(() => {
this.request(method, url, body, options, route, true).then(resolve).catch(reject);
}, Math.floor(Math.random() * 1900 + 100));
return cb();
}
cb();
if (response.length > 0) {
if (resp.headers["content-type"] === "application/json") {
try {
response = JSON.parse(response);
}
catch (err) {
reject(err);
return;
}
}
}
let { stack } = _stackHolder;
if (stack.startsWith("Error\n")) {
stack = stack.substring(6);
}
let err;
if (response.code) {
err = new DiscordRESTError(req, resp, response, stack);
}
else {
err = new DiscordHTTPError(req, resp, response, stack);
}
reject(err);
return;
}
if (response.length > 0) {
if (resp.headers["content-type"] === "application/json") {
try {
response = JSON.parse(response);
}
catch (err) {
cb();
reject(err);
return;
}
}
}
cb();
resolve(response);
});
});
req.setTimeout(this.requestTimeout, () => {
reqError = new Error(`Request timed out (>${this.requestTimeout}ms) on ${method} ${url}`);
req.abort();
});
req.end(data);
};
if (this.globalBlock && (options.auth)) {
this.readyQueue.push(() => {
if (! this.ratelimits[route]) {
this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
}
this.ratelimits[route].queue(actualCall, short);
});
}
else {
if (! this.ratelimits[route]) {
this.ratelimits[route] = new SequentialBucket(1, this.latencyRef);
}
this.ratelimits[route].queue(actualCall, short);
}
});
}
}
module.exports = RequestHandler;

@ -0,0 +1,105 @@
/*
The MIT License (MIT)
Copyright (c) 2016-2020 abalabahaha
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
"use strict";
/**
* Ratelimit requests and release in sequence
* @prop {Number} limit How many tokens the bucket can consume in the current interval
* @prop {Number} remaining How many tokens the bucket has left in the current interval
* @prop {Number} reset Timestamp of next reset
* @prop {Boolean} processing Whether the queue is being processed
*/
class SequentialBucket {
/**
* Construct a SequentialBucket
* @arg {Number} tokenLimit The max number of tokens the bucket can consume per interval
* @arg {Object} [latencyRef] An object
* @arg {Number} latencyRef.latency Interval between consuming tokens
*/
constructor(limit, latencyRef = { latency: 0 }) {
this.limit = this.remaining = limit;
this.resetInterval = 0;
this.reset = 0;
this.processing = false;
this.latencyRef = latencyRef;
this._queue = [];
}
/**
* Queue something in the SequentialBucket
* @arg {Function} func A function to call when a token can be consumed. The function will be passed a callback argument, which must be called to allow the bucket to continue to work
*/
queue(func, short) {
if (short) {
this._queue.unshift(func);
}
else {
this._queue.push(func);
}
this.check();
}
check(override) {
if (this._queue.length === 0) {
if (this.processing) {
clearTimeout(this.processing);
this.processing = false;
}
return;
}
if (this.processing && !override) {
return;
}
const now = Date.now();
const offset = this.latencyRef.latency + (this.latencyRef.offset || 0);
if (!this.reset) {
this.reset = now - offset;
this.remaining = this.limit;
}
else if (this.reset < now - offset) {
this.reset = now - offset + (this.resetInterval || 0);
this.remaining = this.limit;
}
this.last = now;
if (this.remaining <= 0) {
this.processing = setTimeout(() => {
this.processing = false;
this.check(true);
}, Math.max(0, (this.reset || 0) - now) + offset);
return;
}
--this.remaining;
this.processing = true;
this._queue.shift()(() => {
if (this._queue.length > 0) {
this.check(true);
}
else {
this.processing = false;
}
});
}
}
module.exports = SequentialBucket;

@ -0,0 +1,218 @@
"use strict";
const RequestHandler = require("./eris/rest/RequestHandler");
/**
* Make requests to discord's OAuth2 API
* @extends requestHandler
*/
class OAuth extends RequestHandler {
/**
*
* @arg {Object} opts
* @arg {String?} opts.version The version of the Discord API to use. Defaults to v7.
* @arg {Number} [opts.requestTimeout=15000] A number of milliseconds before requests are considered timed out
* @arg {Number} [opts.latencyThreshold=30000] The average request latency at which the RequestHandler will start emitting latency errors
* @arg {Number} [opts.ratelimiterOffset=0] A number of milliseconds to offset the ratelimit timing calculations by
* @arg {String?} opts.clientId Your application's client id
* @arg {String?} opts.clientSecret Your application's client secret
* @arg {String?} opts.redirectUri Your URL redirect uri
* @arg {String?} opts.credentials Base64 encoding of the UTF-8 encoded credentials string of your application
*/
constructor(opts = {}) {
super({
version: opts.version || "v7",
requestTimeout: opts.requestTimeout || 15000,
latencyThreshold: opts.latencyThreshold || 30000,
ratelimiterOffset: opts.ratelimiterOffset || 0,
});
this.client_id = opts.clientId;
this.client_secret = opts.clientSecret;
this.redirect_uri = opts.redirectUri;
this.credentials = opts.credentials;
}
_encode(obj) {
let string = "";
for (const [key, value] of Object.entries(obj)) {
if (!value) continue;
string += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
}
return string.substring(1);
}
/**
* Exchange the code returned by discord in the query for the user access token
* If specified, can also use refresh_token to get a new valid token
* Read discord's OAuth2 documentation for a full example (https://discord.com/developers/docs/topics/oauth2)
* @arg {Object} opts The object containing the parameters for the request
* @arg {String?} opts.clientId Your application's client id
* @arg {String?} opts.clientSecret Your application's client secret
* @arg {String} opts.grantType Either authorization_code or refresh_token
* @arg {String?} opts.code The code from the querystring
* @arg {String?} opts.refreshToken The user's refresh token
* @arg {String?} opts.redirectUri Your URL redirect uri
* @arg {String} opts.scope The scopes requested in your authorization url, space-delimited
* @returns {Promise<Object>}
*/
tokenRequest(opts = {}) {
const obj = {
client_id: opts.clientId || this.client_id,
client_secret: opts.clientSecret || this.client_secret,
grant_type: undefined,
code: undefined,
refresh_token: undefined,
redirect_uri: opts.redirectUri || this.redirect_uri,
scope: opts.scope instanceof Array ? opts.scope.join(" ") : opts.scope,
};
if (opts.grantType === "authorization_code") {
obj.code = opts.code;
obj.grant_type = opts.grantType;
}
else if (opts.grantType === "refresh_token") {
obj.refresh_token = opts.refreshToken;
obj.grant_type = opts.grantType;
}
else throw new Error("Invalid grant_type provided, it must be either authorization_code or refresh_token");
const encoded_string = this._encode(obj);
return this.request("POST", "/oauth2/token", encoded_string, {
contentType: "application/x-www-form-urlencoded",
});
}
/**
* Revoke the user access token
* @arg {String} access_token The user access token
* @arg {String} credentials Base64 encoding of the UTF-8 encoded credentials string of your application
* @returns {Promise<String>}
*/
revokeToken(access_token, credentials) {
if (!credentials && !this.credentials) throw new Error("Missing credentials for revokeToken method");
return this.request("POST", "/oauth2/token/revoke", `token=${access_token}`, {
auth: {
type: "Basic",
creds: credentials || this.credentials,
},
contentType: "application/x-www-form-urlencoded",
});
}
/**
* Request basic user data
* Requires the `identify` scope
* @arg {String} access_token The user access token
* @returns {Promise<Object>}
*/
getUser(access_token) {
return this.request("GET", "/users/@me", undefined, {
auth: {
type: "Bearer",
creds: access_token,
},
contentType: "application/json",
});
}
/**
* Request all the guilds the user is in
* Requires the `guilds` scope
* @arg {String} access_token The user access token
* @returns {Promise<Object[]>}
*/
getUserGuilds(access_token) {
return this.request("GET", "/users/@me/guilds", undefined, {
auth: {
type: "Bearer",
creds: access_token,
},
contentType: "application/json",
});
}
/**
* Request a user's connections
* Requires the `connections` scope
* @arg {String} access_token The user access token
* @returns {Promise<Object[]>}
*/
getUserConnections(access_token) {
return this.request("GET", "/users/@me/connections", undefined, {
auth: {
type: "Bearer",
creds: access_token,
},
contentType: "application/json",
});
}
/**
* Force a user to join a guild
* Requires the `guilds.join` scope
* @arg {Object} opts
* @arg {String} opts.guildId The ID of the guild to join
* @arg {String} opts.userId The ID of the user to be added to the guild
* @arg {Boolean?} opts.deaf Whether the user is deafened in voice channels
* @arg {Boolean?} opts.mute Whether the user is muted in voice channels
* @arg {String?} opts.nickname Value to set users nickname to
* @arg {String[]?} opts.roles Array of role ids the member is assigned
* @arg {String} opts.accessToken The user access token
* @arg {String} opts.botToken The token of the bot used to authenticate
* @returns {Promise<Object | String>}
*/
addMember(opts) {
return this.request("PUT", `/guilds/${opts.guildId}/members/${opts.userId}`, {
deaf: opts.deaf,
mute: opts.mute,
nick: opts.nickname,
roles: opts.roles,
access_token: opts.accessToken,
}, {
auth: {
type: "Bot",
creds: opts.botToken,
},
contentType: "application/json",
});
}
/**
*
* @arg {Object} opts
* @arg {String} opts.clientId Your application's client id
* @arg {String?} opts.prompt Controls how existing authorizations are handled, either consent or none (for passthrough scopes authorization is always required).
* @arg {String?} opts.redirectUri Your URL redirect uri
* @arg {String?} opts.responseType The response type, either code or token (token is for client-side web applications only). Defaults to code
* @arg {String | Array} opts.scope The scopes for your URL
* @arg {String?} opts.state A unique cryptographically secure string (https://discord.com/developers/docs/topics/oauth2#state-and-security)
* @arg {Number?} opts.permissions The permissions number for the bot invite (only with bot scope) (https://discord.com/developers/docs/topics/permissions)
* @arg {String?} opts.guildId The guild id to pre-fill the bot invite (only with bot scope)
* @arg {Boolean?} opts.disableGuildSelect Disallows the user from changing the guild for the bot invite, either true or false (only with bot scope)
* @returns {String}
*/
generateAuthUrl(opts = {}) {
const obj = {
client_id: opts.clientId || this.client_id,
prompt: opts.prompt || undefined,
redirect_uri: opts.redirectUri || this.redirect_uri,
response_type: opts.responseType || "code",
scope: opts.scope instanceof Array ? opts.scope.join(" ") : opts.scope,
permissions: opts.permissions || undefined,
guild_id: opts.guildId || undefined,
disable_guild_select: opts.disableGuildSelect || undefined,
state: opts.state || undefined,
};
const encoded_string = this._encode(obj);
return `https://discord.com/api/oauth2/authorize?${encoded_string}`;
}
}
module.exports = OAuth;

@ -0,0 +1,56 @@
{
"_from": "discord-oauth2",
"_id": "discord-oauth2@2.7.1",
"_inBundle": false,
"_integrity": "sha512-8PiGsieFxujS6FqcDrWtrunhy5LQGIZC6n1Bi58CP/1/rusqxplj3tXMQ2DBZtw/oyDUrJwSBsYGSr7IJJwTeg==",
"_location": "/discord-oauth2",
"_phantomChildren": {},
"_requested": {
"type": "tag",
"registry": true,
"raw": "discord-oauth2",
"name": "discord-oauth2",
"escapedName": "discord-oauth2",
"rawSpec": "",
"saveSpec": null,
"fetchSpec": "latest"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/discord-oauth2/-/discord-oauth2-2.7.1.tgz",
"_shasum": "d71958d6f321c7bebec859ee60fc316fefef7eb7",
"_spec": "discord-oauth2",
"_where": "/home/sigonasr2/divar/server2",
"author": {
"name": "reboxer"
},
"bugs": {
"url": "https://github.com/reboxer/discord-oauth2/issues"
},
"bundleDependencies": false,
"deprecated": false,
"description": "Easily interact with discord's oauth2 API",
"devDependencies": {
"eslint": "7.30.0"
},
"homepage": "https://github.com/reboxer/discord-oauth2#readme",
"keywords": [
"api",
"discord",
"discordapp",
"oauth2"
],
"license": "MIT",
"main": "index.js",
"name": "discord-oauth2",
"repository": {
"type": "git",
"url": "git+https://github.com/reboxer/discord-oauth2.git"
},
"scripts": {
"lint": "eslint --ext .js ./"
},
"version": "2.7.1"
}

@ -1,11 +0,0 @@
{
"name": "secrethash",
"version": "1.0.0",
"main": "secrethash.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": ""
}

5
package-lock.json generated

@ -104,6 +104,11 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
}, },
"discord-oauth2": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/discord-oauth2/-/discord-oauth2-2.7.1.tgz",
"integrity": "sha512-8PiGsieFxujS6FqcDrWtrunhy5LQGIZC6n1Bi58CP/1/rusqxplj3tXMQ2DBZtw/oyDUrJwSBsYGSr7IJJwTeg=="
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",

@ -11,6 +11,7 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.1",
"discord-oauth2": "^2.7.1",
"express": "^4.17.1", "express": "^4.17.1",
"fs": "0.0.1-security", "fs": "0.0.1-security",
"http": "0.0.1-security", "http": "0.0.1-security",

@ -4,7 +4,13 @@ var http = require('http');
var https = require('https'); var https = require('https');
const fs = require('fs'); const fs = require('fs');
const sh = require('secrethash'); const sh = require('./secrethash');
const disc = require("discord-oauth2");
var refreshToken=""
const discord = new disc({
clientId: "885738904685281291",
clientSecret: process.env.NGSPLANNER_CLIENT_SECRET,
redirectUri: "https://localhost:3000#/login",});
var key = fs.readFileSync('./projectdivar.com/privkey1.pem'); var key = fs.readFileSync('./projectdivar.com/privkey1.pem');
var cert = fs.readFileSync('./projectdivar.com/cert1.pem'); var cert = fs.readFileSync('./projectdivar.com/cert1.pem');
@ -427,6 +433,41 @@ for (var test of ["","/test"]) {
res.status(500).send(err.message) res.status(500).send(err.message)
}) })
}) })
app.get(PREFIX+test+"/userData",(req,res)=>{
if (req.query.token) {
discord.tokenRequest({
code:req.query.token,
grantType: "authorization_code",
scope: ["identify", "email"],
})
.then(res2=>{return discord.getUser(res2.access_token)})
.then(res2=>{
//Sample output. We can register the user from here.
//{"id":"176012829076226048","username":"sigonasr2","avatar":"c19b2f2a9d530f9f99efa3b1b573d7ef","discriminator":"6262","public_flags":0,"flags":0,"banner":"e0668c23567d5b58e88ea916306ec6d5","banner_color":null,"accent_color":null,"locale":"en-US","mfa_enabled":false,"premium_type":2,"email":"sigonasr2@gmail.com","verified":true}
/*var obj = {
body:{
recoveryhash:res2.id,
password:req.query.token,
username:res2.username,
avatar:"https://cdn.discordapp.com/avatars/"+res2.id+"/"+res2.avatar+".png",
userID:res2.id,
email:res2.email
}
}
registerUsers(obj,res)*/
res2.token=sh(req.query.token)
res.status(200).json(res2)
})
.catch((err)=>{
//console.log(err.response)
res.status(500).send("Everything is not fine")
})
//res.status(200).send("Everything is fine")
} else {
res.status(500).send("Everything is not fine")
}
})
} }
function CreateDynamicEndpoints() { function CreateDynamicEndpoints() {
@ -824,8 +865,8 @@ function registerUsers(req,res){
return db.query('select * from users where recovery_hash=$1 limit 1',[req.body.recoveryhash]) return db.query('select * from users where recovery_hash=$1 limit 1',[req.body.recoveryhash])
.then((data)=>{ .then((data)=>{
if (data.rows.length>0) { if (data.rows.length>0) {
db.query('update users set password_hash=$2 where id=$1',[data.rows[0].id,req.body.password]) db.query('update users set username=$3,password_hash=$2 where id=$1',[data.rows[0].id,req.body.password,req.body.username])
db2.query('update users set password_hash=$2 where id=$1',[data.rows[0].id,req.body.password]) db2.query('update users set username=$3,password_hash=$2 where id=$1',[data.rows[0].id,req.body.password,req.body.username])
res.status(200).json({verified:true}) res.status(200).json({verified:true})
} else { } else {
res.status(200).json({verified:true}) res.status(200).json({verified:true})
@ -847,10 +888,11 @@ function registerUsers(req,res){
}) })
} else { } else {
console.log("User with email '"+req.body.email+"' already exists assume it's not a google account. Overwriting...") console.log("User with email '"+req.body.email+"' already exists assume it's not a google account. Overwriting...")
db.query('update users set password_hash=$1,avatar=$2,recovery_hash=$3 where id=$4 returning id',[req.body.password,req.body.avatar,req.body.userID,data.rows[0].id]) //console.log(req.body.password)
db.query('update users set password_hash=$1,avatar=$2,recovery_hash=$3,username=$5 where id=$4 returning id',[req.body.password,req.body.avatar,req.body.userID,data.rows[0].id,req.body.username])
.then((data)=>{ .then((data)=>{
if (data.rows.length>0) { if (data.rows.length>0) {
db2.query('update users set password_hash=$1,avatar=$2,recovery_hash=$3 where id=$4 returning id',[req.body.password,req.body.avatar,req.body.userID,data.rows[0].id]) db2.query('update users set password_hash=$1,avatar=$2,recovery_hash=$3,username=$5 where id=$4 returning id',[req.body.password,req.body.avatar,req.body.userID,data.rows[0].id,req.body.username])
} }
}) })
res.status(200).json({verified:true}) res.status(200).json({verified:true})
@ -865,9 +907,10 @@ function registerUsers(req,res){
} }
app.post(PREFIX+"/registerUser",registerUsers) app.post(PREFIX+"/registerUser",registerUsers)
app.post(PREFIX+"/test/registerUser",registerUsers)
app.post(PREFIX+"/validUser",(req,res)=>{ function validUser(req,res) {
//console.log(sh.SecretHash("098f6bcd4621d373cade4e832627b4f6")) //console.log(sh("098f6bcd4621d373cade4e832627b4f6"))
if (req.body.recoveryhash&&req.body.password) { if (req.body.recoveryhash&&req.body.password) {
//A recovery hash means this is an external login. Try seeing if it matches something. //A recovery hash means this is an external login. Try seeing if it matches something.
db.query('select * from users where recovery_hash=$1 and password_hash=$2 limit 1',[req.body.recoveryhash,req.body.password]) db.query('select * from users where recovery_hash=$1 and password_hash=$2 limit 1',[req.body.recoveryhash,req.body.password])
@ -882,7 +925,7 @@ app.post(PREFIX+"/validUser",(req,res)=>{
res.status(500).send(err.message) res.status(500).send(err.message)
}) })
} else { } else {
db.query('select * from users where username=$1 and password_hash=$2 limit 1',[req.body.username,sh.SecretHash(req.body.password)]) db.query('select * from users where username=$1 and password_hash=$2 limit 1',[req.body.username,sh(req.body.password)])
.then((data)=>{ .then((data)=>{
if (data.rows.length>0) { if (data.rows.length>0) {
res.status(200).json({verified:true}) res.status(200).json({verified:true})
@ -894,7 +937,10 @@ app.post(PREFIX+"/validUser",(req,res)=>{
res.status(500).send(err.message) res.status(500).send(err.message)
}) })
} }
}) }
app.post(PREFIX+"/validUser",validUser)
app.post(PREFIX+"/test/validUser",validUser)
app.post(PREFIX+"/saveskilltree",(req,res)=>{ app.post(PREFIX+"/saveskilltree",(req,res)=>{
db4.query('select * from password where password=$1',[req.body.pass]) db4.query('select * from password where password=$1',[req.body.pass])
@ -953,7 +999,7 @@ function submitBuild(req,res,db,send) {
db.query('select users.username from builds join users on users_id=users.id where builds.id=$1',[req.body.id]) db.query('select users.username from builds join users on users_id=users.id where builds.id=$1',[req.body.id])
.then((data)=>{ .then((data)=>{
console.log(data.rows) console.log(data.rows)
if (data.rows.length>0&&data.rows[0].username===req.body.username&&data.rows[0].password_hash===sh.SecretHash(req.body.pass)) { if (data.rows.length>0&&data.rows[0].username===req.body.username&&data.rows[0].password_hash===sh(req.body.pass)) {
return db.query('update builds set creator=$1,build_name=$2,class1=(SELECT id from class WHERE name=$3 limit 1),class2=(SELECT id from class WHERE name=$4 limit 1),last_modified=$5,data=$6 where id=$7 returning id',[req.body.creator,req.body.build_name,req.body.class1,req.body.class2,new Date(),req.body.data,req.body.id]) return db.query('update builds set creator=$1,build_name=$2,class1=(SELECT id from class WHERE name=$3 limit 1),class2=(SELECT id from class WHERE name=$4 limit 1),last_modified=$5,data=$6 where id=$7 returning id',[req.body.creator,req.body.build_name,req.body.class1,req.body.class2,new Date(),req.body.data,req.body.id])
.then((data)=>{ .then((data)=>{
if (send) { if (send) {

Loading…
Cancel
Save