@@ -169,7 +169,7 @@ async function canAccessUnit(user_id, unit_id) {
|
||||
attributes: ['course_id'],
|
||||
include: [{ model: Course, as: 'course', attributes: [], where: { status: 'published', ...notDeleted }, required: true }],
|
||||
});
|
||||
if (!links.length) return !unit?.subscription;
|
||||
if (!links.length) return !unit?.subscription || unit.subscription === 'free';
|
||||
for (const link of links) {
|
||||
if (await canAccessCourse(user_id, link.course_id)) return true;
|
||||
}
|
||||
@@ -185,7 +185,7 @@ async function canAccessLesson(user_id, lesson_id) {
|
||||
if (await hasActivePurchase(user_id, 'lesson', lesson_id)) return true;
|
||||
|
||||
const unitLinks = await UnitLesson.findAll({ where: { lesson_id }, attributes: ['unit_id'] });
|
||||
if (!unitLinks.length) return !lesson?.subscription;
|
||||
if (!unitLinks.length) return !lesson?.subscription || lesson.subscription === 'free';
|
||||
for (const link of unitLinks) {
|
||||
if (await canAccessUnit(user_id, link.unit_id)) return true;
|
||||
}
|
||||
|
||||
@@ -97,7 +97,17 @@ function pipeRemoteStream(remoteUrl, req, res) {
|
||||
let clientClosed = false;
|
||||
|
||||
const proxyReq = transport.request(remoteUrl, { headers: proxyHeaders }, (proxyRes) => {
|
||||
const status = proxyRes.statusCode === 206 ? 206 : 200;
|
||||
const status = proxyRes.statusCode ?? 502;
|
||||
|
||||
// Upstream (Garage/S3) returned something other than a successful
|
||||
// content response — surface the real failure instead of piping its
|
||||
// (often tiny XML/JSON) error body through as if it were the file.
|
||||
if (status !== 200 && status !== 206) {
|
||||
proxyRes.resume(); // drain so the socket can close cleanly
|
||||
console.error(`[CLIENT][MEDIA][PROXY] Upstream returned ${status} for ${remoteUrl}`);
|
||||
if (!res.headersSent) res.status(502).json({ message: "Stream unavailable." });
|
||||
return;
|
||||
}
|
||||
|
||||
[
|
||||
"content-type",
|
||||
@@ -210,9 +220,10 @@ exports.issueToken = async (req, res) => {
|
||||
// 3. Requester IP matches the IP that issued the token
|
||||
//
|
||||
// Range requests for the same token are allowed (browser seeking).
|
||||
// TEMPORARY:
|
||||
// Same with problem from s3.service.js (Line 168-171)
|
||||
// Investigate the issue ourselves.
|
||||
// pipeRemoteStream() above forwards the real upstream status instead of
|
||||
// collapsing everything to 200 — see its non-200/206 branch. A similar
|
||||
// swallowed-status issue may still exist in s3.service.js (~line 168-171),
|
||||
// not addressed here.
|
||||
|
||||
exports.streamAsset = async (req, res) => {
|
||||
const { token } = req.params;
|
||||
|
||||
Reference in New Issue
Block a user