@crowdin/app-project-module
Version:
Module that generates for you all common endpoints for serving standalone Crowdin App
104 lines (103 loc) • 4.95 kB
JavaScript
;
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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRequestCredentialsMasker = getRequestCredentialsMasker;
exports.maskKey = maskKey;
exports.postRequestCredentialsMasker = postRequestCredentialsMasker;
const index_1 = require("../index");
const crowdin_client_1 = require("../middlewares/crowdin-client");
const token_1 = require("./app-functions/token");
const index_2 = require("./index");
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);
}
function getMaskableFieldsKeys(moduleConfig) {
if (!moduleConfig.formUiSchema) {
return [];
}
return Object.keys(moduleConfig.formUiSchema).filter((fieldKey) => { var _a, _b; return ((_b = (_a = moduleConfig === null || moduleConfig === void 0 ? void 0 : moduleConfig.formUiSchema) === null || _a === void 0 ? void 0 : _a[fieldKey]) === null || _b === void 0 ? void 0 : _b['ui:widget']) === 'password'; });
}
function getRequestCredentialsMasker({ moduleConfig, dataPath = 'formData', }) {
return function (req, res, next) {
if (req.__credentialsMaskerApplied) {
return next();
}
req.__credentialsMaskerApplied = true;
// we can't find "password" fields without ui schema
if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) {
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();
};
}
function postRequestCredentialsMasker({ secret, moduleConfig, credentialsExtractor, }) {
return (0, index_2.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
var _a;
if (req.__credentialsMaskerApplied) {
return next();
}
req.__credentialsMaskerApplied = true;
if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) {
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, token_1.validateJwtToken)(jwtToken, secret);
const crowdinId = `${jwtPayload.context.organization_id}`;
unmaskedFields = yield index_1.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);
}));
}