Spaces:
Build error
Build error
File size: 4,103 Bytes
0bfe2e3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import { Request, Response, NextFunction } from 'express';
import {
createLogger,
APIError,
constants,
Env,
decryptString,
validateConfig,
Resource,
} from '@aiostreams/core';
import { UserDataSchema, UserRepository, UserData } from '@aiostreams/core';
import { StremioTransformer } from '@aiostreams/core';
const logger = createLogger('server');
// Valid resources that require authentication
// const VALID_RESOURCES = ['stream', 'configure'];
const VALID_RESOURCES = [...constants.RESOURCES, 'manifest.json', 'configure'];
export const userDataMiddleware = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { uuid, encryptedPassword } = req.params;
// Both uuid and encryptedPassword should be present since we mounted the router on this path
if (!uuid || !encryptedPassword) {
next(new APIError(constants.ErrorCode.USER_NOT_FOUND));
return;
}
// First check - validate path has two components followed by valid resource
const resourceRegex = new RegExp(`/(${VALID_RESOURCES.join('|')})`);
const resourceMatch = req.path.match(resourceRegex);
if (!resourceMatch) {
next();
return;
}
// Second check - validate UUID format (simpler regex that just checks UUID format)
const uuidRegex =
/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
if (!uuidRegex.test(uuid)) {
next(new APIError(constants.ErrorCode.USER_NOT_FOUND));
return;
}
const resource = resourceMatch[1];
try {
// Check if user exists
const userExists = await UserRepository.checkUserExists(uuid);
if (!userExists) {
if (constants.RESOURCES.includes(resource as Resource)) {
res.status(200).json(
StremioTransformer.createDynamicError(resource as Resource, {
errorDescription: 'User not found',
})
);
return;
}
next(new APIError(constants.ErrorCode.USER_NOT_FOUND));
return;
}
let password = undefined;
// decrypt the encrypted password
const { success: successfulDecryption, data: decryptedPassword } =
decryptString(encryptedPassword!);
if (!successfulDecryption) {
if (constants.RESOURCES.includes(resource as Resource)) {
res.status(200).json(
StremioTransformer.createDynamicError(resource as Resource, {
errorDescription: 'Invalid password',
})
);
return;
}
next(new APIError(constants.ErrorCode.USER_ERROR));
return;
}
// Get and validate user data
let userData = await UserRepository.getUser(uuid, decryptedPassword);
if (!userData) {
if (constants.RESOURCES.includes(resource as Resource)) {
res.status(200).json(
StremioTransformer.createDynamicError(resource as Resource, {
errorDescription: 'Invalid password',
})
);
return;
}
next(new APIError(constants.ErrorCode.USER_INVALID_PASSWORD));
return;
}
userData.encryptedPassword = encryptedPassword;
userData.uuid = uuid;
if (resource !== 'configure') {
try {
userData = await validateConfig(userData, true, true);
} catch (error: any) {
if (constants.RESOURCES.includes(resource as Resource)) {
res.status(200).json(
StremioTransformer.createDynamicError(resource as Resource, {
errorDescription: error.message,
})
);
return;
}
logger.error(`Invalid config for ${uuid}: ${error.message}`);
next(
new APIError(
constants.ErrorCode.USER_INVALID_CONFIG,
undefined,
error.message
)
);
return;
}
}
// Attach validated data to request
req.userData = userData;
req.userData.ip = req.userIp;
req.uuid = uuid;
next();
} catch (error: any) {
logger.error(error.message);
if (error instanceof APIError) {
next(error);
} else {
next(new APIError(constants.ErrorCode.INTERNAL_SERVER_ERROR));
}
}
};
|