UNPKG

@di-zed/yandex-smart-home

Version:

The Yandex Smart Home skills for the different device types.

238 lines (237 loc) 8.76 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const appError_1 = __importDefault(require("../errors/appError")); const configProvider_1 = __importDefault(require("../providers/configProvider")); const clientRepository_1 = __importDefault(require("../repositories/clientRepository")); const userRepository_1 = __importDefault(require("../repositories/userRepository")); /** * Authorization Controller. */ class AuthController { /** * Protect Middleware. * * @param req * @param res * @param next * @returns void */ protect(req, res, next) { return __awaiter(this, void 0, void 0, function* () { let token = ''; if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) { token = req.headers.authorization.split(' ')[1]; } if (!token) { return next(new appError_1.default(res.__('You are not logged in! Please log in to get access.'), 401)); } try { const tokenData = yield this.verifyToken(token); req.currentClient = yield clientRepository_1.default.getClientById(tokenData.appId); req.currentUser = yield userRepository_1.default.getUserById(tokenData.userId); } catch (err) { return next(new appError_1.default(res.__('You are not logged in! Please log in to get access.'), 401)); } return next(); }); } /** * GET Method. * Get Login Form. * https://yandex.ru/dev/dialogs/alice/doc/auth/how-it-works.html?lang=en * * @param req * @param res * @param next * @returns void */ login(req, res, next) { return __awaiter(this, void 0, void 0, function* () { const authParams = this.getAuthParams(req.query); if (!this.isAuthRequestValid(authParams)) { return next(new appError_1.default(res.__('Invalid input data.'), 400)); } try { yield clientRepository_1.default.getClientByClientId(authParams.client_id); } catch (err) { return next(new appError_1.default(res.__('This client does not exist.'), 404)); } const viewAuthLogin = configProvider_1.default.getConfigOption('viewAuthLogin'); return res.status(200).render(viewAuthLogin || 'auth/login', { title: res.__('Log into your account'), params: authParams, error: req.query.error || '', }); }); } /** * POST Method. * Authorization Action. * https://yandex.ru/dev/dialogs/alice/doc/auth/how-it-works.html?lang=en#authorization * * @param req * @param res * @param next * @returns void */ loginPost(req, res, next) { return __awaiter(this, void 0, void 0, function* () { const authParams = this.getAuthParams(req.body); if (!this.isAuthRequestValid(authParams)) { return next(new appError_1.default(res.__('Invalid input data.'), 400)); } const { email, password } = req.body; const loginUrl = '/auth/login?' + new URLSearchParams(authParams).toString(); if (!email || !password) { return res.redirect(loginUrl + '&error=email'); } let client; let user; try { client = yield clientRepository_1.default.getClientByClientId(authParams.client_id); } catch (err) { return next(new appError_1.default(res.__('This client does not exist.'), 404)); } try { user = yield userRepository_1.default.getUserByEmailAndPassword(email, password); } catch (err) { return res.redirect(loginUrl + '&error=email'); } return res.status(301).redirect(authParams.redirect_uri + '?' + new URLSearchParams({ code: this.signToken(client.id, user.id, '2 days'), state: authParams.state, client_id: authParams.client_id, scope: authParams.scope, }).toString()); }); } /** * POST Method. * Get Token Information. * https://yandex.ru/dev/dialogs/alice/doc/auth/how-it-works.html?lang=en * * This example shows getting an OAuth token in the web service. * https://yandex.ru/dev/direct/doc/examples-v5/php5-file_get_contents-token.html?lang=en * * @param req * @param res * @param next * @returns Response */ token(req, res, next) { return __awaiter(this, void 0, void 0, function* () { const code = req.body.code; if (!code) { return next(new appError_1.default(res.__('The parameter "%s" is required.', 'code'), 400)); } try { const codeData = yield this.verifyToken(code); const client = yield clientRepository_1.default.getClientById(codeData.appId); const user = yield userRepository_1.default.getUserById(codeData.userId); return res.status(200).json({ access_token: this.signToken(client.id, user.id, '365 days'), token_type: 'bearer', expires_in: 60 * 60 * 24 * 365, }); } catch (err) { return next(new appError_1.default(res.__('Page Not Found.'), 404)); } }); } /** * Get Auth Parameters. * * @param data * @returns AuthParams * @protected */ getAuthParams(data) { return { state: data.state || '', redirect_uri: data.redirect_uri || '', response_type: data.response_type || '', client_id: data.client_id || '', scope: data.scope || '', }; } /** * Is the Authentication Request valid? * * @param authParams * @returns boolean * @protected */ isAuthRequestValid(authParams) { let isValid = true; const requiredFields = ['state', 'redirect_uri', 'response_type', 'client_id']; const authParamKeys = Object.keys(authParams); authParamKeys.forEach((key) => { const value = authParams[key]; if (requiredFields.includes(key) && !value) { isValid = false; } }); if (!authParams.redirect_uri.startsWith(process.env.YANDEX_DIALOG_URI)) { isValid = false; } return isValid; } /** * Sign Token. * * @param appId * @param userId * @param expiresIn * @returns string * @protected */ signToken(appId, userId, expiresIn) { const tokenData = { appId: appId, userId: userId, }; return jsonwebtoken_1.default.sign(tokenData, process.env.JWT_SECRET, { expiresIn: expiresIn, }); } /** * Verify Token. * * @param token * @returns Promise<TokenData> * @protected */ verifyToken(token) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { jsonwebtoken_1.default.verify(token, process.env.JWT_SECRET, {}, (err, payload) => { if (err) { return reject(err); } return resolve(payload); }); }); }); } } exports.default = AuthController;