| Server IP : 167.235.67.158 / Your IP : 216.73.216.95 Web Server : Apache System : Linux ubuntu-8gb-nbg1-1 6.8.0-111-generic #111-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 11 23:16:02 UTC 2026 x86_64 User : upstairsbar.co.uk ( 982) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/api.pda.the-word.com/common/ |
Upload File : |
function getMethod(event) {
return event.httpMethod || event.requestContext?.http?.method || 'GET';
}
function normalizePath(event) {
let path = event.rawPath || event.path || '/';
const stagePrefix = process.env.API_STAGE ? `/${process.env.API_STAGE}` : '';
if (stagePrefix && path.startsWith(stagePrefix)) {
path = path.slice(stagePrefix.length) || '/';
}
if (path.length > 1 && path.endsWith('/')) {
path = path.slice(0, -1);
}
return path || '/';
}
function getHeader(headers = {}, name) {
const target = name.toLowerCase();
const foundKey = Object.keys(headers).find((key) => key.toLowerCase() === target);
return foundKey ? headers[foundKey] : undefined;
}
function extractBearerToken(headers = {}) {
const header = getHeader(headers, 'authorization');
if (!header || !header.startsWith('Bearer ')) {
return null;
}
return header.slice('Bearer '.length).trim();
}
function parseJsonBody(event) {
if (!event.body) {
return {};
}
if (typeof event.body === 'object') {
const sanitizedBody = sanitizeInput(event.body);
logJsonBody(event, event.body, sanitizedBody);
return sanitizedBody;
}
try {
const parsedBody = JSON.parse(event.body);
const sanitizedBody = sanitizeInput(parsedBody);
logJsonBody(event, parsedBody, sanitizedBody);
return sanitizedBody;
} catch (error) {
const wrapped = new Error('Invalid JSON body.');
wrapped.statusCode = 400;
throw wrapped;
}
}
const UNSAFE_INPUT_CHARACTERS = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u00AD\u061C\u200B-\u200F\u202A-\u202E\u2060-\u206F\uFEFF]/g;
const SENSITIVE_FIELD_PATTERN = /password|token|secret|authorization|api[-_]?key/i;
function sanitizeInput(value) {
if (typeof value === 'string') {
return value.replace(UNSAFE_INPUT_CHARACTERS, '');
}
if (Array.isArray(value)) {
return value.map(sanitizeInput);
}
if (value && typeof value === 'object') {
return Object.fromEntries(
Object.entries(value).map(([key, entryValue]) => [key, sanitizeInput(entryValue)])
);
}
return value;
}
function logJsonBody(event, parsedBody, sanitizedBody) {
if (process.env.LOG_JSON_BODY !== 'true') {
return;
}
console.log(JSON.stringify({
level: 'debug',
message: 'json body received',
extra: {
method: getMethod(event),
path: normalizePath(event),
parsedBody: redactSensitiveFields(parsedBody),
sanitizedBody: redactSensitiveFields(sanitizedBody),
unsafeCharacters: findUnsafeCharacters(parsedBody)
},
timestamp: new Date().toISOString()
}));
}
function redactSensitiveFields(value, key = '') {
if (SENSITIVE_FIELD_PATTERN.test(key)) {
return '[REDACTED]';
}
if (Array.isArray(value)) {
return value.map((entry) => redactSensitiveFields(entry));
}
if (value && typeof value === 'object') {
return Object.fromEntries(
Object.entries(value).map(([entryKey, entryValue]) => [entryKey, redactSensitiveFields(entryValue, entryKey)])
);
}
return value;
}
function findUnsafeCharacters(value, path = '$') {
if (typeof value === 'string') {
const matches = [];
for (const match of value.matchAll(UNSAFE_INPUT_CHARACTERS)) {
matches.push({
path,
index: match.index,
codePoint: `U+${match[0].codePointAt(0).toString(16).toUpperCase().padStart(4, '0')}`
});
}
return matches;
}
if (Array.isArray(value)) {
return value.flatMap((entry, index) => findUnsafeCharacters(entry, `${path}[${index}]`));
}
if (value && typeof value === 'object') {
return Object.entries(value).flatMap(([key, entryValue]) => findUnsafeCharacters(entryValue, `${path}.${key}`));
}
return [];
}
function formatResponse({ statusCode = 200, body = {}, headers = {} }) {
return {
statusCode,
headers: {
'content-type': 'application/json',
...headers
},
body: typeof body === 'string' ? JSON.stringify({ message: body }) : JSON.stringify(body)
};
}
function requireFields(body, fields) {
const missing = fields.filter((field) => body[field] === undefined || body[field] === null || body[field] === '');
if (missing.length > 0) {
const error = new Error(`Missing required fields: ${missing.join(', ')}`);
error.statusCode = 400;
throw error;
}
}
function isoOrNull(value) {
if (!value) {
return null;
}
return new Date(value).toISOString();
}
function toMysqlDateTime(value) {
const date = value instanceof Date ? value : new Date(value);
if (Number.isNaN(date.getTime())) {
const error = new Error('Invalid date value.');
error.statusCode = 400;
throw error;
}
const yyyy = date.getUTCFullYear();
const mm = String(date.getUTCMonth() + 1).padStart(2, '0');
const dd = String(date.getUTCDate()).padStart(2, '0');
const hh = String(date.getUTCHours()).padStart(2, '0');
const mi = String(date.getUTCMinutes()).padStart(2, '0');
const ss = String(date.getUTCSeconds()).padStart(2, '0');
const ms = String(date.getUTCMilliseconds()).padStart(3, '0');
return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}.${ms}`;
}
function parseInteger(value, defaultValue, { min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER } = {}) {
const parsed = Number.parseInt(value, 10);
if (!Number.isFinite(parsed)) {
return defaultValue;
}
return Math.min(Math.max(parsed, min), max);
}
module.exports = {
extractBearerToken,
formatResponse,
getHeader,
getMethod,
isoOrNull,
normalizePath,
parseInteger,
parseJsonBody,
requireFields,
sanitizeInput,
toMysqlDateTime
};