refactor checkToken
This commit is contained in:
parent
8a3989c297
commit
f1f68c3d31
@ -2390,12 +2390,16 @@
|
|||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"flags": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"color",
|
"color",
|
||||||
|
"flags",
|
||||||
"guild",
|
"guild",
|
||||||
"guild_id",
|
"guild_id",
|
||||||
"hoist",
|
"hoist",
|
||||||
@ -3632,47 +3636,45 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"roles": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/Role"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"banner": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"unavailable": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"channels": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/Channel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"region": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"icon": {
|
"icon": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"system_channel_id": {
|
"parent": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"rules_channel_id": {
|
"owner_id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"afk_timeout": {
|
"nsfw": {
|
||||||
"type": "integer"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
"explicit_content_filter": {
|
"invites": {
|
||||||
"type": "integer"
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Invite"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"voice_states": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/VoiceState"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"webhooks": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Webhook"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"_do_validate": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
"assign": {
|
"assign": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@ -3707,6 +3709,39 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
},
|
},
|
||||||
|
"roles": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Role"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"banner": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"unavailable": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"channels": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Channel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"region": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"system_channel_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"rules_channel_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"afk_timeout": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"explicit_content_filter": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"afk_channel_id": {
|
"afk_channel_id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -3773,30 +3808,9 @@
|
|||||||
"$ref": "#/components/schemas/Sticker"
|
"$ref": "#/components/schemas/Sticker"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"invites": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/Invite"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"voice_states": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/VoiceState"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"webhooks": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/Webhook"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mfa_level": {
|
"mfa_level": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"owner_id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"preferred_locale": {
|
"preferred_locale": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -3830,21 +3844,11 @@
|
|||||||
"nsfw_level": {
|
"nsfw_level": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"nsfw": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"parent": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"premium_progress_bar_enabled": {
|
"premium_progress_bar_enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
|
||||||
"_do_validate": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@ -4173,7 +4177,9 @@
|
|||||||
"channel": {
|
"channel": {
|
||||||
"$ref": "#/components/schemas/RateLimitOptions"
|
"$ref": "#/components/schemas/RateLimitOptions"
|
||||||
},
|
},
|
||||||
"auth": {}
|
"auth": {
|
||||||
|
"$ref": "#/components/schemas/AuthRateLimit"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"auth",
|
"auth",
|
||||||
@ -4182,6 +4188,21 @@
|
|||||||
"webhook"
|
"webhook"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"AuthRateLimit": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"login": {
|
||||||
|
"$ref": "#/components/schemas/RateLimitOptions"
|
||||||
|
},
|
||||||
|
"register": {
|
||||||
|
"$ref": "#/components/schemas/RateLimitOptions"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"login",
|
||||||
|
"register"
|
||||||
|
]
|
||||||
|
},
|
||||||
"GlobalRateLimits": {
|
"GlobalRateLimits": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -4664,13 +4685,13 @@
|
|||||||
"discovery_splash": {
|
"discovery_splash": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"region": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"icon": {
|
"icon": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"nullable": true
|
"nullable": true
|
||||||
},
|
},
|
||||||
|
"region": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"guild_template_code": {
|
"guild_template_code": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -5406,6 +5427,12 @@
|
|||||||
},
|
},
|
||||||
"promotional_email_opt_in": {
|
"promotional_email_opt_in": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"unique_username_registration": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"global_name": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@ -5684,13 +5711,6 @@
|
|||||||
"version": {
|
"version": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"guild_id": {
|
|
||||||
"type": "string",
|
|
||||||
"nullable": true
|
|
||||||
},
|
|
||||||
"flags": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"message_notifications": {
|
"message_notifications": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
@ -5716,6 +5736,13 @@
|
|||||||
"suppress_roles": {
|
"suppress_roles": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"guild_id": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"mute_scheduled_events": {
|
"mute_scheduled_events": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
@ -6934,6 +6961,9 @@
|
|||||||
"APIPrivateUser": {
|
"APIPrivateUser": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"flags": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -6980,9 +7010,6 @@
|
|||||||
"pronouns": {
|
"pronouns": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"flags": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"mfa_enabled": {
|
"mfa_enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
@ -7051,6 +7078,9 @@
|
|||||||
"newToken": {
|
"newToken": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"flags": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -7097,9 +7127,6 @@
|
|||||||
"pronouns": {
|
"pronouns": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"flags": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"mfa_enabled": {
|
"mfa_enabled": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
@ -7264,10 +7291,10 @@
|
|||||||
"APIPublicMember": {
|
"APIPublicMember": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"guild_id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"guild_id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"nick": {
|
"nick": {
|
||||||
@ -7696,10 +7723,10 @@
|
|||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"guild_id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"guild_id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"nick": {
|
"nick": {
|
||||||
|
18812
assets/schemas.json
18812
assets/schemas.json
File diff suppressed because it is too large
Load Diff
@ -92,12 +92,7 @@ export async function Authentication(
|
|||||||
Sentry.setUser({ id: req.user_id });
|
Sentry.setUser({ id: req.user_id });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { jwtSecret } = Config.get().security;
|
const { decoded, user } = await checkToken(req.headers.authorization);
|
||||||
|
|
||||||
const { decoded, user } = await checkToken(
|
|
||||||
req.headers.authorization,
|
|
||||||
jwtSecret,
|
|
||||||
);
|
|
||||||
|
|
||||||
req.token = decoded;
|
req.token = decoded;
|
||||||
req.user_id = decoded.id;
|
req.user_id = decoded.id;
|
||||||
|
@ -48,11 +48,9 @@ router.post(
|
|||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
const { password, token } = req.body as PasswordResetSchema;
|
const { password, token } = req.body as PasswordResetSchema;
|
||||||
|
|
||||||
const { jwtSecret } = Config.get().security;
|
|
||||||
|
|
||||||
let user;
|
let user;
|
||||||
try {
|
try {
|
||||||
const userTokenData = await checkToken(token, jwtSecret, true);
|
const userTokenData = await checkToken(token);
|
||||||
user = userTokenData.user;
|
user = userTokenData.user;
|
||||||
} catch {
|
} catch {
|
||||||
throw FieldErrors({
|
throw FieldErrors({
|
||||||
|
@ -78,11 +78,10 @@ router.post(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { jwtSecret } = Config.get().security;
|
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userTokenData = await checkToken(token, jwtSecret, true);
|
const userTokenData = await checkToken(token);
|
||||||
user = userTokenData.user;
|
user = userTokenData.user;
|
||||||
} catch {
|
} catch {
|
||||||
throw FieldErrors({
|
throw FieldErrors({
|
||||||
|
@ -30,7 +30,6 @@ import {
|
|||||||
Intents,
|
Intents,
|
||||||
Member,
|
Member,
|
||||||
ReadyEventData,
|
ReadyEventData,
|
||||||
User,
|
|
||||||
Session,
|
Session,
|
||||||
EVENTEnum,
|
EVENTEnum,
|
||||||
Config,
|
Config,
|
||||||
@ -60,17 +59,6 @@ import { check } from "./instanceOf";
|
|||||||
// TODO: user sharding
|
// TODO: user sharding
|
||||||
// TODO: check privileged intents, if defined in the config
|
// TODO: check privileged intents, if defined in the config
|
||||||
|
|
||||||
const getUserFromToken = async (token: string): Promise<string | null> => {
|
|
||||||
try {
|
|
||||||
const { jwtSecret } = Config.get().security;
|
|
||||||
const { decoded } = await checkToken(token, jwtSecret);
|
|
||||||
return decoded.id;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`[Gateway] Invalid token`, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function onIdentify(this: WebSocket, data: Payload) {
|
export async function onIdentify(this: WebSocket, data: Payload) {
|
||||||
if (this.user_id) {
|
if (this.user_id) {
|
||||||
// we've already identified
|
// we've already identified
|
||||||
@ -85,12 +73,12 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
|||||||
|
|
||||||
this.capabilities = new Capabilities(identify.capabilities || 0);
|
this.capabilities = new Capabilities(identify.capabilities || 0);
|
||||||
|
|
||||||
// Check auth
|
const { user } = await checkToken(identify.token, {
|
||||||
// TODO: the checkToken call will fetch user, and then we have to refetch with different select
|
relations: ["relationships", "relationships.to", "settings"],
|
||||||
// checkToken should be able to select what we want
|
select: [...PrivateUserProjection, "relationships"],
|
||||||
const user_id = await getUserFromToken(identify.token);
|
});
|
||||||
if (!user_id) return this.close(CLOSECODES.Authentication_failed);
|
if (!user) return this.close(CLOSECODES.Authentication_failed);
|
||||||
this.user_id = user_id;
|
this.user_id = user.id;
|
||||||
|
|
||||||
// Check intents
|
// Check intents
|
||||||
if (!identify.intents) identify.intents = 30064771071n; // TODO: what is this number?
|
if (!identify.intents) identify.intents = 30064771071n; // TODO: what is this number?
|
||||||
@ -112,7 +100,7 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
|||||||
) {
|
) {
|
||||||
// TODO: why do we even care about this right now?
|
// TODO: why do we even care about this right now?
|
||||||
console.log(
|
console.log(
|
||||||
`[Gateway] Invalid sharding from ${user_id}: ${identify.shard}`,
|
`[Gateway] Invalid sharding from ${user.id}: ${identify.shard}`,
|
||||||
);
|
);
|
||||||
return this.close(CLOSECODES.Invalid_shard);
|
return this.close(CLOSECODES.Invalid_shard);
|
||||||
}
|
}
|
||||||
@ -132,22 +120,14 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Get from database:
|
// Get from database:
|
||||||
// * the current user,
|
|
||||||
// * the users read states
|
// * the users read states
|
||||||
// * guild members for this user
|
// * guild members for this user
|
||||||
// * recipients ( dm channels )
|
// * recipients ( dm channels )
|
||||||
// * the bot application, if it exists
|
// * the bot application, if it exists
|
||||||
const [, user, application, read_states, members, recipients] =
|
const [, application, read_states, members, recipients] = await Promise.all(
|
||||||
await Promise.all([
|
[
|
||||||
session.save(),
|
session.save(),
|
||||||
|
|
||||||
// TODO: Refactor checkToken to allow us to skip this additional query
|
|
||||||
User.findOneOrFail({
|
|
||||||
where: { id: this.user_id },
|
|
||||||
relations: ["relationships", "relationships.to", "settings"],
|
|
||||||
select: [...PrivateUserProjection, "relationships"],
|
|
||||||
}),
|
|
||||||
|
|
||||||
Application.findOne({
|
Application.findOne({
|
||||||
where: { id: this.user_id },
|
where: { id: this.user_id },
|
||||||
select: ["id", "flags"],
|
select: ["id", "flags"],
|
||||||
@ -224,7 +204,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
|
|
||||||
// We forgot to migrate user settings from the JSON column of `users`
|
// We forgot to migrate user settings from the JSON column of `users`
|
||||||
// to the `user_settings` table theyre in now,
|
// to the `user_settings` table theyre in now,
|
||||||
@ -407,6 +388,17 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
|||||||
merged_members: merged_members,
|
merged_members: merged_members,
|
||||||
sessions: allSessions,
|
sessions: allSessions,
|
||||||
|
|
||||||
|
resume_gateway_url:
|
||||||
|
Config.get().gateway.endpointClient ||
|
||||||
|
Config.get().gateway.endpointPublic ||
|
||||||
|
"ws://127.0.0.1:3001",
|
||||||
|
|
||||||
|
// lol hack whatever
|
||||||
|
required_action:
|
||||||
|
Config.get().login.requireVerification && !user.verified
|
||||||
|
? "REQUIRE_VERIFIED_EMAIL"
|
||||||
|
: undefined,
|
||||||
|
|
||||||
consents: {
|
consents: {
|
||||||
personalization: {
|
personalization: {
|
||||||
consented: false, // TODO
|
consented: false, // TODO
|
||||||
@ -421,18 +413,8 @@ export async function onIdentify(this: WebSocket, data: Payload) {
|
|||||||
friend_suggestion_count: 0,
|
friend_suggestion_count: 0,
|
||||||
analytics_token: "",
|
analytics_token: "",
|
||||||
tutorial: null,
|
tutorial: null,
|
||||||
resume_gateway_url:
|
|
||||||
Config.get().gateway.endpointClient ||
|
|
||||||
Config.get().gateway.endpointPublic ||
|
|
||||||
"ws://127.0.0.1:3001",
|
|
||||||
session_type: "normal", // TODO
|
session_type: "normal", // TODO
|
||||||
auth_session_id_hash: "", // TODO
|
auth_session_id_hash: "", // TODO
|
||||||
|
|
||||||
// lol hack whatever
|
|
||||||
required_action:
|
|
||||||
Config.get().login.requireVerification && !user.verified
|
|
||||||
? "REQUIRE_VERIFIED_EMAIL"
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Send READY
|
// Send READY
|
||||||
|
@ -42,4 +42,8 @@ export interface RegisterSchema {
|
|||||||
captcha_key?: string;
|
captcha_key?: string;
|
||||||
|
|
||||||
promotional_email_opt_in?: boolean;
|
promotional_email_opt_in?: boolean;
|
||||||
|
|
||||||
|
// part of pomelo
|
||||||
|
unique_username_registration?: boolean;
|
||||||
|
global_name?: string;
|
||||||
}
|
}
|
||||||
|
@ -19,94 +19,66 @@
|
|||||||
import jwt, { VerifyOptions } from "jsonwebtoken";
|
import jwt, { VerifyOptions } from "jsonwebtoken";
|
||||||
import { Config } from "./Config";
|
import { Config } from "./Config";
|
||||||
import { User } from "../entities";
|
import { User } from "../entities";
|
||||||
|
// TODO: dont use deprecated APIs lol
|
||||||
|
import {
|
||||||
|
FindOptionsRelationByString,
|
||||||
|
FindOptionsSelectByString,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
|
export const JWTOptions: VerifyOptions = { algorithms: ["HS256"] };
|
||||||
|
|
||||||
export type UserTokenData = {
|
export type UserTokenData = {
|
||||||
user: User;
|
user: User;
|
||||||
decoded: { id: string; iat: number };
|
decoded: { id: string; iat: number; email?: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
async function checkEmailToken(
|
export const checkToken = (
|
||||||
decoded: jwt.JwtPayload,
|
|
||||||
): Promise<UserTokenData> {
|
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
|
||||||
return new Promise(async (res, rej) => {
|
|
||||||
if (!decoded.iat) return rej("Invalid Token"); // will never happen, just for typings.
|
|
||||||
|
|
||||||
const user = await User.findOne({
|
|
||||||
where: {
|
|
||||||
email: decoded.email,
|
|
||||||
},
|
|
||||||
select: [
|
|
||||||
"email",
|
|
||||||
"id",
|
|
||||||
"verified",
|
|
||||||
"deleted",
|
|
||||||
"disabled",
|
|
||||||
"username",
|
|
||||||
"data",
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) return rej("Invalid Token");
|
|
||||||
|
|
||||||
if (new Date().getTime() > decoded.iat * 1000 + 86400 * 1000)
|
|
||||||
return rej("Invalid Token");
|
|
||||||
|
|
||||||
// Using as here because we assert `id` and `iat` are in decoded.
|
|
||||||
// TS just doesn't want to assume its there, though.
|
|
||||||
return res({ decoded, user } as UserTokenData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkToken(
|
|
||||||
token: string,
|
token: string,
|
||||||
jwtSecret: string,
|
opts?: {
|
||||||
isEmailVerification = false,
|
select?: FindOptionsSelectByString<User>;
|
||||||
): Promise<UserTokenData> {
|
relations?: FindOptionsRelationByString;
|
||||||
return new Promise((res, rej) => {
|
},
|
||||||
token = token.replace("Bot ", "");
|
): Promise<UserTokenData> =>
|
||||||
token = token.replace("Bearer ", "");
|
new Promise((resolve, reject) => {
|
||||||
/**
|
jwt.verify(
|
||||||
in spacebar, even with instances that have bot distinction; we won't enforce "Bot" prefix,
|
token,
|
||||||
as we don't really have separate pathways for bots
|
Config.get().security.jwtSecret,
|
||||||
**/
|
JWTOptions,
|
||||||
|
async (err, out) => {
|
||||||
|
const decoded = out as UserTokenData["decoded"];
|
||||||
|
if (err || !decoded) return reject("Invalid Token");
|
||||||
|
|
||||||
jwt.verify(token, jwtSecret, JWTOptions, async (err, decoded) => {
|
const user = await User.findOne({
|
||||||
if (err || !decoded) return rej("Invalid Token");
|
where: decoded.email
|
||||||
if (
|
? { email: decoded.email }
|
||||||
typeof decoded == "string" ||
|
: { id: decoded.id },
|
||||||
!("id" in decoded) ||
|
select: [
|
||||||
!decoded.iat
|
...(opts?.select || []),
|
||||||
)
|
"bot",
|
||||||
return rej("Invalid Token"); // will never happen, just for typings.
|
"disabled",
|
||||||
|
"deleted",
|
||||||
|
"rights",
|
||||||
|
"data",
|
||||||
|
],
|
||||||
|
relations: opts?.relations,
|
||||||
|
});
|
||||||
|
|
||||||
if (isEmailVerification) return res(checkEmailToken(decoded));
|
if (!user) return reject("User not found");
|
||||||
|
|
||||||
const user = await User.findOne({
|
// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
|
||||||
where: { id: decoded.id },
|
if (
|
||||||
select: ["data", "bot", "disabled", "deleted", "rights"],
|
decoded.iat * 1000 <
|
||||||
});
|
new Date(user.data.valid_tokens_since).setSeconds(0, 0)
|
||||||
|
)
|
||||||
|
return reject("Invalid Token");
|
||||||
|
|
||||||
if (!user) return rej("Invalid Token");
|
if (user.disabled) return reject("User disabled");
|
||||||
|
if (user.deleted) return reject("User not found");
|
||||||
|
|
||||||
// we need to round it to seconds as it saved as seconds in jwt iat and valid_tokens_since is stored in milliseconds
|
return resolve({ decoded, user });
|
||||||
if (
|
},
|
||||||
decoded.iat * 1000 <
|
);
|
||||||
new Date(user.data.valid_tokens_since).setSeconds(0, 0)
|
|
||||||
)
|
|
||||||
return rej("Invalid Token");
|
|
||||||
|
|
||||||
if (user.disabled) return rej("User disabled");
|
|
||||||
if (user.deleted) return rej("User not found");
|
|
||||||
|
|
||||||
// Using as here because we assert `id` and `iat` are in decoded.
|
|
||||||
// TS just doesn't want to assume its there, though.
|
|
||||||
return res({ decoded, user } as UserTokenData);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
export async function generateToken(id: string, email?: string) {
|
export async function generateToken(id: string, email?: string) {
|
||||||
const iat = Math.floor(Date.now() / 1000);
|
const iat = Math.floor(Date.now() / 1000);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user