dalexhd/SteamSpeak

View on GitHub
packages/server/src/core/Website/api/controllers/verify.ts

Summary

Maintainability
B
5 hrs
Test Coverage
import Events from '@core/Events';
import lang from '@locales/index';
import crypto from 'crypto';
import Cache from '@core/Cache';
import { findClients } from './auth';
import log from '@utils/log';
import VerifiedClient from '@core/Database/models/verifiedClient';
import { Request, Response } from 'express';

/**
 * Check request secret.
 *
 * @param {Request} req The express request instance
 * @returns {Promise<any>}
 */
const findSecret = async function (req: Request): Promise<any> {
    const secret = req.body.secret;
    const steamData = JSON.parse((await Cache.get(`verification:${secret}`)) as string);
    if (steamData === null) throw { statusCode: 404, message: lang.error.invalid_token };
    return steamData;
};

/**
 * Check if the user is connected to the server.
 *
 * @param {Request} req The express request instance
 * @param {Response} res The express response instance
 * @returns {Promise<any>}
 */
export const check = async function (req: Request, res: Response): Promise<any> {
    log.info('Received verification check request from remote.', { type: 'website' });
    try {
        const steamData = await findSecret(req);
        const clients = await findClients(req, {
            clientType: 0
        });
        res.status(200).json({ steam: steamData, clients });
    } catch (error) {
        res.status(error.statusCode || 401).json({
            status: 'error',
            message: error.message
        });
    }
};

/**
 * Send to the selected user a secret validation token.
 *
 * @param {Request} req The express request instance
 * @param {Response} res The express response instance
 * @returns {Promise<any>}
 */
export const send = async function (req: Request, res: Response): Promise<any> {
    log.info(`Received verification send request to ${req.body.dbid} from remote.`, {
        type: 'website'
    });
    try {
        const steamData = await findSecret(req);
        const [client] = await findClients(req, {
            clientType: 0,
            clientDatabaseId: req.body.dbid
        });
        const token = crypto.randomBytes(3).toString('hex');
        client
            .message(
                lang.message.verify_msg.replaceArray(
                    ['{NICKNAME}', '{STEAM_NICKNAME}', '{TOKEN}'],
                    [client.nickname, steamData.player_name, token]
                )
            )
            .then(() => {
                Cache.set(
                    `${client.databaseId}:verifyToken`,
                    JSON.stringify({
                        ip: client.connectionClientIp,
                        token
                    }),
                    'ex',
                    600
                );
                res.status(200).end();
            });
    } catch (error) {
        res.status(error.statusCode || 400).json({
            status: 'error',
            message: error.message
        });
    }
};

/**
 * Login with specified user
 *
 * @param {Request} req The express request instance
 * @param {Response} res The express response instance
 * @returns {Promise<any>}
 */
export const login = async function (req: Request, res: Response): Promise<any> {
    log.info(`Received login request from ${req.body.dbid}.`, { type: 'website' });
    try {
        const steamData = await findSecret(req);
        const [client] = await findClients(req, {
            clientType: 0,
            clientDatabaseId: req.body.dbid
        });
        const sendCache = JSON.parse((await Cache.get(`${client.databaseId}:verifyToken`)) as string);

        if (typeof sendCache === 'undefined')
            throw { statusCode: 500, message: lang.error.unexpected_verification_error };
        if (sendCache.token !== req.body.token) {
            throw { statusCode: 403, message: lang.error.invalid_password };
        } else if (sendCache.ip !== client.connectionClientIp) {
            throw { statusCode: 403, message: lang.error.ip_mismatch };
        } else {
            log.success(`${client.nickname} verified successfully!`, { type: 'website' });
            VerifiedClient.create({
                uid: client.uniqueIdentifier,
                dbid: client.databaseId,
                steamId: steamData.steamId
            });
            Events.emit('verificationSuccess', steamData.steamId, client.databaseId);
            client.message(lang.message.success_verification);
            Cache.del(
                `${client.databaseId}:verifyToken`,
                `verification:${req.body.secret}`,
                `shadow:verification:${req.body.secret}`
            );
            res.status(201).json({
                status: 'success',
                message: lang.message.success_verification
            });
        }
    } catch (error) {
        res.status(error.statusCode || 400).json({
            status: 'error',
            message: error.message
        });
    }
};