a simple web player for subsonic
tinysub.devins.page
subsonic
navidrome
javascript
1// input validation for server URLs and credentials
2
3// ensure value is always an array
4const toArray = (value) =>
5 Array.isArray(value) ? value : value ? [value] : [];
6
7// build validation response object
8const buildValidation = (valid, value, error) => ({
9 valid,
10 ...(valid ? { value } : { error }),
11});
12
13// check if id is present and valid type
14function validateId(value, fieldName = "ID") {
15 const isValid =
16 value && (typeof value === "string" || typeof value === "number");
17 return buildValidation(isValid, value, `${fieldName} is required`);
18}
19
20// validate server URL is valid HTTP(S) format
21function validateServerUrl(url) {
22 if (!url || typeof url !== "string") {
23 return buildValidation(false, null, STRINGS.SERVER_URL_REQUIRED);
24 }
25
26 const trimmed = url.trim();
27 if (!trimmed) {
28 return buildValidation(false, null, STRINGS.SERVER_URL_EMPTY);
29 }
30
31 try {
32 const urlObj = new URL(trimmed);
33 const isValid = ["http:", "https:"].includes(urlObj.protocol);
34 return buildValidation(
35 isValid,
36 trimmed,
37 isValid ? null : "Server URL must use HTTP or HTTPS",
38 );
39 } catch {
40 return buildValidation(false, null, "Invalid URL format");
41 }
42}
43
44// validate username and password meet requirements
45function validateCredentials(username, password) {
46 const errors = [];
47
48 if (!username || typeof username !== "string" || !username.trim()) {
49 errors.push("Username is required");
50 } else if (username.length > 255) {
51 errors.push("Username is too long (max 255 characters)");
52 }
53
54 if (!password || typeof password !== "string" || !password) {
55 errors.push("Password is required");
56 } else if (password.length > 1000) {
57 errors.push("Password is too long");
58 }
59
60 if (errors.length > 0) {
61 return buildValidation(false, null, errors.join("; "));
62 }
63
64 return buildValidation(true, { username: username.trim(), password });
65}