UNPKG

@crowdin/app-project-module

Version:

Module that generates for you all common endpoints for serving standalone Crowdin App

111 lines (110 loc) 5.14 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 }); exports.maskKey = exports.postRequestCredentialsMasker = exports.getRequestCredentialsMasker = void 0; const lodash_get_1 = __importDefault(require("lodash.get")); const index_1 = require("./index"); const index_2 = require("../index"); const crowdin_client_1 = require("../middlewares/crowdin-client"); const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions"); function maskKey(key) { const maskWith = '*'; const unmaskedCharsAtEnd = 3; const repeatCount = key.length > unmaskedCharsAtEnd ? key.length - unmaskedCharsAtEnd : 0; return maskWith.repeat(repeatCount) + key.substring(key.length - 3); } exports.maskKey = maskKey; function getMaskableFieldsKeys(moduleConfig) { if (!moduleConfig.formUiSchema) { return []; } return Object.keys(moduleConfig.formUiSchema).filter((fieldKey) => { return (0, lodash_get_1.default)(moduleConfig, `formUiSchema[${fieldKey}]['ui:widget']`) === 'password'; }); } function getRequestCredentialsMasker({ moduleConfig, dataPath = 'formData', }) { return function (req, res, next) { // we can't find "password" fields without ui schema if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) { return next(); } // temporary if (!moduleConfig.maskPasswords) { return next(); } const maskableFieldsKeys = getMaskableFieldsKeys(moduleConfig); if (!maskableFieldsKeys.length) { return next(); } const originalSend = res.send; res.send = function (body) { const maskFields = (target) => { maskableFieldsKeys.forEach((fieldKey) => { if (target[fieldKey]) { target[fieldKey] = maskKey(target[fieldKey]); } }); }; if (body[dataPath]) { maskFields(body[dataPath]); } if (dataPath === '') { maskFields(body); } return originalSend.apply(res, [body]); }; return next(); }; } exports.getRequestCredentialsMasker = getRequestCredentialsMasker; function postRequestCredentialsMasker(moduleConfig, credentialsExtractor) { return (0, index_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () { var _a; if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) { return next(); } // temporary if (!moduleConfig.maskPasswords) { return next(); } const fieldsKeysInRequest = Object.keys(((_a = req.body) === null || _a === void 0 ? void 0 : _a.data) || []); let unmaskedFields = {}; if (credentialsExtractor) { unmaskedFields = yield credentialsExtractor(req, res); } else { // most common way of storing data const jwtToken = (0, crowdin_client_1.getToken)(req) || ''; const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, process.env.CROWDIN_CLIENT_SECRET || ''); const crowdinId = `${jwtPayload.context.organization_id}`; unmaskedFields = yield index_2.metadataStore.getMetadata(`form-data-${crowdinId}`); } unmaskedFields = unmaskedFields || {}; const maskableFieldsKeys = getMaskableFieldsKeys(moduleConfig); Object.keys(unmaskedFields).forEach((fieldKey) => { if (!maskableFieldsKeys.includes(fieldKey) || !fieldsKeysInRequest.includes(fieldKey)) { delete unmaskedFields[fieldKey]; } }); req.body.data = Object.assign(Object.assign({}, req.body.data), Object.keys(unmaskedFields).reduce((acc, key) => { if (maskKey(unmaskedFields[key]) === req.body.data[key]) { acc[key] = unmaskedFields[key]; } return acc; }, {})); // run getRequestCredentialsMasker to mask fields that can be in response return getRequestCredentialsMasker({ moduleConfig })(req, res, next); })); } exports.postRequestCredentialsMasker = postRequestCredentialsMasker;