mirror of
https://github.com/HeyPuter/puter.git
synced 2026-10-07 20:31:50 +00:00
162 lines
5.0 KiB
JavaScript
162 lines
5.0 KiB
JavaScript
/**
|
|
* Copyright (C) 2024-present Puter Technologies Inc.
|
|
*
|
|
* This file is part of Puter.
|
|
*
|
|
* Puter is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import { HttpError } from '../core/http/HttpError.js';
|
|
|
|
/**
|
|
* Small input validation utilities for driver methods.
|
|
* Throws HttpError(400, ...) on failure. Returns the value on success.
|
|
*/
|
|
|
|
export function validateString(
|
|
value,
|
|
{ key, maxLen, regex, required = true, allowEmpty = false } = {},
|
|
) {
|
|
if (value === undefined || value === null) {
|
|
if (required)
|
|
throw new HttpError(400, `Missing \`${key}\``, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
return value;
|
|
}
|
|
if (typeof value !== 'string') {
|
|
throw new HttpError(400, `\`${key}\` must be a string`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
if (!allowEmpty && value.length === 0) {
|
|
throw new HttpError(400, `\`${key}\` must not be empty`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
if (maxLen && value.length > maxLen) {
|
|
throw new HttpError(
|
|
400,
|
|
`\`${key}\` must be at most ${maxLen} characters`,
|
|
{ legacyCode: 'bad_request' },
|
|
);
|
|
}
|
|
if (regex && !regex.test(value)) {
|
|
throw new HttpError(400, `\`${key}\` has an invalid format`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function validateUrl(
|
|
value,
|
|
{
|
|
key,
|
|
maxLen = 3000,
|
|
required = true,
|
|
// Default allowlist is http(s) only — anything else is an XSS/SSRF
|
|
// primitive when the value is later consumed as `iframe.src`,
|
|
// `window.location`, a server-side fetch, etc. `new URL()` alone
|
|
// happily parses `javascript:alert(1)`, `data:text/html,…`,
|
|
// `file:///etc/passwd`, and `vbscript:`; callers that need
|
|
// something exotic must opt in explicitly.
|
|
protocols = ['http:', 'https:'],
|
|
} = {},
|
|
) {
|
|
if (value === undefined || value === null) {
|
|
if (required)
|
|
throw new HttpError(400, `Missing \`${key}\``, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
return value;
|
|
}
|
|
validateString(value, { key, maxLen, required });
|
|
let parsed;
|
|
try {
|
|
parsed = new URL(value);
|
|
} catch {
|
|
throw new HttpError(400, `\`${key}\` must be a valid URL`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
if (!protocols.includes(parsed.protocol)) {
|
|
throw new HttpError(
|
|
400,
|
|
`\`${key}\` must use one of the following protocols: ${protocols.join(', ')}`,
|
|
{ legacyCode: 'bad_request' },
|
|
);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function validateBool(value, { key, required = false } = {}) {
|
|
if (value === undefined || value === null) {
|
|
if (required)
|
|
throw new HttpError(400, `Missing \`${key}\``, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
return value;
|
|
}
|
|
return Boolean(value);
|
|
}
|
|
|
|
export function validateJsonObject(value, { key, required = false } = {}) {
|
|
if (value === undefined || value === null) {
|
|
if (required)
|
|
throw new HttpError(400, `Missing \`${key}\``, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
return value;
|
|
}
|
|
if (typeof value === 'string') {
|
|
try {
|
|
value = JSON.parse(value);
|
|
} catch {
|
|
throw new HttpError(400, `\`${key}\` must be valid JSON`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
}
|
|
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
throw new HttpError(400, `\`${key}\` must be an object`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function validateArrayOfStrings(value, { key, required = false } = {}) {
|
|
if (value === undefined || value === null) {
|
|
if (required)
|
|
throw new HttpError(400, `Missing \`${key}\``, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
return value;
|
|
}
|
|
if (!Array.isArray(value)) {
|
|
throw new HttpError(400, `\`${key}\` must be an array`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
for (let i = 0; i < value.length; i++) {
|
|
if (typeof value[i] !== 'string') {
|
|
throw new HttpError(400, `\`${key}[${i}]\` must be a string`, {
|
|
legacyCode: 'bad_request',
|
|
});
|
|
}
|
|
}
|
|
return value;
|
|
}
|