Add onboarding weather and template gradients
This commit is contained in:
+87
-14
@@ -62,11 +62,15 @@ function registerPlayerRoutes(app, options) {
|
||||
body: body
|
||||
}));
|
||||
|
||||
if (req.headers['x-pulse-page-auth']) {
|
||||
headers['x-pulse-page-auth'] = String(req.headers['x-pulse-page-auth']).trim();
|
||||
const requestHeaders = req && req.headers ? req.headers : {};
|
||||
if (requestHeaders['x-pulse-page-auth']) {
|
||||
headers['x-pulse-page-auth'] = String(requestHeaders['x-pulse-page-auth']).trim();
|
||||
}
|
||||
if (req.headers['if-none-match']) {
|
||||
headers['if-none-match'] = String(req.headers['if-none-match']).trim();
|
||||
if (requestHeaders['if-none-match']) {
|
||||
headers['if-none-match'] = String(requestHeaders['if-none-match']).trim();
|
||||
}
|
||||
if (requestHeaders['x-pulse-client-id']) {
|
||||
headers['x-pulse-client-id'] = String(requestHeaders['x-pulse-client-id']).trim();
|
||||
}
|
||||
if (requestOptions.contentType) {
|
||||
headers['content-type'] = requestOptions.contentType;
|
||||
@@ -96,6 +100,76 @@ function registerPlayerRoutes(app, options) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getBoundScreenSlug(req) {
|
||||
if (!playerDeviceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const clientId = String(req.query && req.query.clientId || '').trim();
|
||||
if (!clientId) {
|
||||
return null;
|
||||
}
|
||||
const bindingId = clientId;
|
||||
|
||||
if (bridgeBaseUrl) {
|
||||
const response = await fetchBridge(req, '/api/onboarding/status?deviceId=' + encodeURIComponent(bindingId), {
|
||||
method: 'GET'
|
||||
});
|
||||
const status = await readJsonResponse(response);
|
||||
return status && status.screenSlug ? String(status.screenSlug).trim() : null;
|
||||
}
|
||||
|
||||
const [rows] = await pool.query(
|
||||
`SELECT s.slug
|
||||
FROM d_onboarding_devices d
|
||||
JOIN d_screens s ON s.id = d.screen_id
|
||||
WHERE d.device_id = ?`,
|
||||
[bindingId]
|
||||
);
|
||||
return rows[0] && rows[0].slug ? String(rows[0].slug).trim() : null;
|
||||
}
|
||||
|
||||
async function isClientAuthorizedForScreen(req, requestedSlug) {
|
||||
const clientId = String(req.headers['x-pulse-client-id'] || '').trim();
|
||||
if (!clientId) {
|
||||
return false;
|
||||
}
|
||||
const boundSlug = await getBoundScreenSlug({ query: { clientId: clientId } });
|
||||
return boundSlug === String(requestedSlug || '').trim();
|
||||
}
|
||||
|
||||
function isAuthorizedScreenMove(req, requestedSlug) {
|
||||
const queryToken = String(req.query && req.query.moveToken || '').trim();
|
||||
const cookieHeader = String(req.headers && req.headers.cookie || '');
|
||||
const cookieToken = cookieHeader.split(';').map(function (part) {
|
||||
const separator = part.indexOf('=');
|
||||
return separator === -1 ? null : [part.slice(0, separator).trim(), part.slice(separator + 1).trim()];
|
||||
}).filter(Boolean).find(function (entry) { return entry[0] === 'pulse-screen-move'; });
|
||||
const token = queryToken || (cookieToken ? decodeURIComponent(cookieToken[1]) : '');
|
||||
if (!token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const payload = verifyPageAuthToken(token);
|
||||
return Boolean(payload
|
||||
&& String(payload.scope || '').trim() === 'screen-move'
|
||||
&& String(payload.playerId || '').trim() === String(playerDeviceId || '').trim()
|
||||
&& String(payload.screenSlug || '').trim() === String(requestedSlug || '').trim());
|
||||
}
|
||||
|
||||
app.post('/api/screen-move-authorize', express.json(), function (req, res) {
|
||||
const token = String(req.body && req.body.moveToken || '').trim();
|
||||
const payload = verifyPageAuthToken(token);
|
||||
if (!payload
|
||||
|| String(payload.scope || '').trim() !== 'screen-move'
|
||||
|| String(payload.playerId || '').trim() !== String(playerDeviceId || '').trim()) {
|
||||
return res.status(401).json({ error: 'Invalid screen move authorization.' });
|
||||
}
|
||||
|
||||
res.setHeader('Set-Cookie', `pulse-screen-move=${encodeURIComponent(token)}; Max-Age=60; Path=/; HttpOnly; SameSite=Lax`);
|
||||
return res.json({ ok: true });
|
||||
});
|
||||
|
||||
function requirePageAuth(allowedScopes) {
|
||||
return function (req, res, next) {
|
||||
if (!sharedSecret) {
|
||||
@@ -296,7 +370,7 @@ function registerPlayerRoutes(app, options) {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/screen/:slug', function (req, res) {
|
||||
app.get('/screen/:slug', async function (req, res, next) {
|
||||
if (onPlayerPublicBaseUrl) {
|
||||
try {
|
||||
onPlayerPublicBaseUrl(getPlayerPublicBaseUrl(req, null));
|
||||
@@ -321,7 +395,7 @@ function registerPlayerRoutes(app, options) {
|
||||
res.set('X-Player-Offline', '1');
|
||||
return res.send(common.renderPlayerPage(req.params.slug, null));
|
||||
}
|
||||
res.send(common.renderPlayerPage(req.params.slug, data));
|
||||
res.send(common.renderPlayerPage(req.params.slug, null));
|
||||
}).catch(function (error) {
|
||||
if (!isBridgeFetchError(error)) {
|
||||
console.error(error);
|
||||
@@ -332,15 +406,8 @@ function registerPlayerRoutes(app, options) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { bindPlayerToScreen } = require('./onboarding');
|
||||
if (playerDeviceId) {
|
||||
void bindPlayerToScreen(pool, playerDeviceId, req.params.slug)
|
||||
.catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
playerPlaylistService.buildScreenPlaylist(req.params.slug).then(function (data) {
|
||||
res.send(common.renderPlayerPage(req.params.slug, data));
|
||||
res.send(common.renderPlayerPage(req.params.slug, null));
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
res.set('X-Player-Offline', '1');
|
||||
@@ -405,6 +472,9 @@ function registerPlayerRoutes(app, options) {
|
||||
|
||||
app.get('/api/screens/:slug/playlist', requirePageAuth(['player']), async function (req, res, next) {
|
||||
try {
|
||||
if (playerDeviceId && !(await isClientAuthorizedForScreen(req, req.params.slug))) {
|
||||
return res.status(403).json({ error: 'This browser tab is not authorized for this screen.' });
|
||||
}
|
||||
if (bridgeBaseUrl) {
|
||||
const response = await fetchBridge(req, '/api/screens/' + encodeURIComponent(req.params.slug) + '/playlist', {
|
||||
method: 'GET'
|
||||
@@ -448,6 +518,9 @@ function registerPlayerRoutes(app, options) {
|
||||
|
||||
app.get('/api/screens/:slug/announcement', requirePageAuth(['player']), async function (req, res, next) {
|
||||
try {
|
||||
if (playerDeviceId && !(await isClientAuthorizedForScreen(req, req.params.slug))) {
|
||||
return res.status(403).json({ error: 'This browser tab is not authorized for this screen.' });
|
||||
}
|
||||
if (bridgeBaseUrl) {
|
||||
const response = await fetchBridge(req, '/api/screens/' + encodeURIComponent(req.params.slug) + '/announcement', {
|
||||
method: 'GET'
|
||||
|
||||
Reference in New Issue
Block a user